Before :
foreach ($nestedAttributes as $property => $serializedPath) {
    
    if (null === $value = $propertyAccessor->getValue($normalizedData, $serializedPath)) {
    ...
After :
foreach ($nestedAttributes as $property => $serializedPath) {
    if ($serializedPath->getElement(0) === '@parentKey') {
        if (!isset($context['deserialization_path'])) {
            throw new \Error('Deserialized objet have no parent');
        }
        preg_match("/\[(?'key'\w*)\]$/", $context['deserialization_path'], $matches);
        if (!isset($matches['key'])) {
            throw new \Error('Deserialized objet is not emmbed in array');
        }
        $value = $matches['key'];
     } elseif (null === $value = $propertyAccessor->getValue($normalizedData, $serializedPath)) {
    ...
class ItemDTO
{
    #[SerializedPath('[@parentKey]')]
    public ?string $slug = null;
    public ?string $name = null;
    public ?string $description = null;
}
How it works ?
It's a little hack that use the SerializedPath attribute to communicate with the ObjectNormaliser with a custom special path '@parentKey'.
The new object normalizer detect this path and look in the deserialization context to find the key value.
How to improve ?
The best symfony way would be a new tag to do the job. But it needs to create multiple new files like AttributeMetadata, AttributeLoader down to ObjectNormalizer and inject them into right services.