diff --git a/src/LocalData/AbstractLocalDataPostEventSubscriber.php b/src/LocalData/AbstractLocalDataPostEventSubscriber.php
index 0879e34f4a70f04dda2aab13732fadf692f46f98..1ab264497d3e507735b6d984acbfeb51c786a476 100644
--- a/src/LocalData/AbstractLocalDataPostEventSubscriber.php
+++ b/src/LocalData/AbstractLocalDataPostEventSubscriber.php
@@ -21,13 +21,13 @@ use Symfony\Component\HttpFoundation\Response;
 abstract class AbstractLocalDataPostEventSubscriber extends AbstractAuthorizationService implements EventSubscriberInterface
 {
     protected const ROOT_CONFIG_NODE = 'local_data_mapping';
-    protected const SOURCE_ATTRIBUTE_CONFIG_NODE = 'source_attribute';
+    protected const SOURCE_ATTRIBUTES_CONFIG_NODE = 'source_attributes';
     protected const LOCAL_DATA_ATTRIBUTE_CONFIG_NODE = 'local_data_attribute';
     protected const AUTHORIZATION_EXPRESSION_CONFIG_NODE = 'authorization_expression';
     protected const DEFAULT_VALUE_ATTRIBUTE_CONFIG_NODE = 'default_value';
     protected const DEFAULT_VALUES_ATTRIBUTE_CONFIG_NODE = 'default_values';
 
-    private const SOURCE_ATTRIBUTE_KEY = 'source';
+    private const SOURCE_ATTRIBUTES_KEY = 'source';
     private const DEFAULT_VALUE_KEY = 'default';
 
     /*
@@ -57,10 +57,16 @@ abstract class AbstractLocalDataPostEventSubscriber extends AbstractAuthorizatio
             }
 
             $attributeMapEntry = [];
-            $attributeMapEntry[self::SOURCE_ATTRIBUTE_KEY] = $configMappingEntry[self::SOURCE_ATTRIBUTE_CONFIG_NODE];
+            $attributeMapEntry[self::SOURCE_ATTRIBUTES_KEY] = $configMappingEntry[self::SOURCE_ATTRIBUTES_CONFIG_NODE];
+
+            $defaultValue = $configMappingEntry[self::DEFAULT_VALUE_ATTRIBUTE_CONFIG_NODE] ?? null;
+            if ($defaultValue === null) {
+                $defaultArray = $configMappingEntry[self::DEFAULT_VALUES_ATTRIBUTE_CONFIG_NODE] ?? null;
+                if ($defaultArray !== null && $defaultArray !== self::ARRAY_VALUE_NOT_SPECIFIED) {
+                    $defaultValue = $defaultArray;
+                }
+            }
 
-            $defaultValue = $configMappingEntry[self::DEFAULT_VALUE_ATTRIBUTE_CONFIG_NODE] ??
-                ((($defaultArray = $configMappingEntry[self::DEFAULT_VALUES_ATTRIBUTE_CONFIG_NODE]) !== self::ARRAY_VALUE_NOT_SPECIFIED) ? $defaultArray : null);
             if ($defaultValue !== null) {
                 $attributeMapEntry[self::DEFAULT_VALUE_KEY] = $defaultValue;
             }
@@ -97,12 +103,19 @@ abstract class AbstractLocalDataPostEventSubscriber extends AbstractAuthorizatio
                     throw ApiError::withDetails(Response::HTTP_UNAUTHORIZED, sprintf('access to local data attribute \'%s\' denied', $localDataAttributeName));
                 }
 
-                $sourceAttributeName = $attributeMapEntry[self::SOURCE_ATTRIBUTE_KEY];
-                $attributeValue = $sourceData[$sourceAttributeName] ?? $attributeMapEntry[self::DEFAULT_VALUE_KEY] ?? null;
+                $attributeValue = null;
+                foreach ($attributeMapEntry[self::SOURCE_ATTRIBUTES_KEY] as $sourceAttributeName) {
+                    if (($value = $sourceData[$sourceAttributeName] ?? null) !== null) {
+                        $attributeValue = $value;
+                        break;
+                    }
+                }
+
+                $attributeValue = $attributeValue ?? $attributeMapEntry[self::DEFAULT_VALUE_KEY] ?? null;
                 if ($attributeValue !== null) {
                     $postEvent->setLocalDataAttribute($localDataAttributeName, $attributeValue);
                 } else {
-                    throw ApiError::withDetails(Response::HTTP_INTERNAL_SERVER_ERROR, sprintf('attribute \'%s\' not available in source data', $sourceAttributeName));
+                    throw ApiError::withDetails(Response::HTTP_INTERNAL_SERVER_ERROR, sprintf('none of the source attributes available for local data attribute \'%s\'', $localDataAttributeName));
                 }
             }
         }
@@ -123,17 +136,23 @@ abstract class AbstractLocalDataPostEventSubscriber extends AbstractAuthorizatio
         return $treeBuilder->getRootNode()
             ->arrayPrototype()
                 ->children()
-                    ->scalarNode(self::SOURCE_ATTRIBUTE_CONFIG_NODE)->end()
-                    ->scalarNode(self::LOCAL_DATA_ATTRIBUTE_CONFIG_NODE)->end()
+                    ->scalarNode(self::LOCAL_DATA_ATTRIBUTE_CONFIG_NODE)
+                        ->info('The name of the local data attribute.')
+                    ->end()
+                    ->arrayNode(self::SOURCE_ATTRIBUTES_CONFIG_NODE)
+                        ->info('The list of source attributes to map to the local data attribute ordered by preferred usage. If an attribute is not found, the next attribute in the list is used.')
+                        ->scalarPrototype()->end()
+                    ->end()
                     ->scalarNode(self::AUTHORIZATION_EXPRESSION_CONFIG_NODE)
                         ->defaultValue('false')
+                        ->info('A boolean expression evaluable by the Symfony Expression Language determining whether the current user may request read the local data attribute.')
                     ->end()
                     ->scalarNode(self::DEFAULT_VALUE_ATTRIBUTE_CONFIG_NODE)
-                        ->info('The default value for scalar (non-array) attributes. If none is specified, an exception is thrown in the case the source attribute is not found.')
+                        ->info('The default value for scalar (i.e. non-array) attributes. If none is specified, an exception is thrown in case none of the source attributes is found.')
                     ->end()
                     ->arrayNode(self::DEFAULT_VALUES_ATTRIBUTE_CONFIG_NODE)
                         ->defaultValue(self::ARRAY_VALUE_NOT_SPECIFIED)
-                        ->info('The default value for array type attributes. If none is specified, an exception is thrown in the case the source attribute is not found.')
+                        ->info('The default value for array type attributes. If none is specified, an exception is thrown in case none of the source attributes is found.')
                         ->scalarPrototype()->end()
                     ->end()
                 ->end()
diff --git a/src/LocalData/LocalDataEventDispatcher.php b/src/LocalData/LocalDataEventDispatcher.php
index fb174d30d6b7afa4bc0595413c29f0c9ba65b7dc..0e60a3dc06d5dd4ad80eab1c85e9b7335383d78f 100644
--- a/src/LocalData/LocalDataEventDispatcher.php
+++ b/src/LocalData/LocalDataEventDispatcher.php
@@ -30,14 +30,15 @@ class LocalDataEventDispatcher
     private $eventDispatcher;
 
     /**
-     * @param string                   $resourceClass   The class name of the entity (resource) this event dispatcher is responsible for
-     * @param EventDispatcherInterface $eventDispatcher The inner event dispatcher that this event dispatcher decorates
+     * @param string                   $resourceClass    The class name of the entity (resource) this event dispatcher is responsible for
+     * @param EventDispatcherInterface $eventDispatcher  The inner event dispatcher that this event dispatcher decorates
+     * @param string|null              $uniqueEntityName The unique name of the entity. If not specified or empty, the 'shortName' attribute of the entities @ApiResource annotation is used.
      */
-    public function __construct(string $resourceClass, EventDispatcherInterface $eventDispatcher)
+    public function __construct(string $resourceClass, EventDispatcherInterface $eventDispatcher, string $uniqueEntityName = null)
     {
         $this->queryParameters = [];
         $this->requestedAttributes = [];
-        $this->uniqueEntityName = self::getUniqueEntityName($resourceClass);
+        $this->uniqueEntityName = !Tools::isNullOrEmpty($uniqueEntityName) ? $uniqueEntityName : self::getUniqueEntityName($resourceClass);
         $this->eventDispatcher = $eventDispatcher;
     }
 
@@ -113,7 +114,7 @@ class LocalDataEventDispatcher
         }
 
         $uniqueName = $resourceMetadata->getShortName() ?? '';
-        if (empty($uniqueName)) {
+        if (Tools::isNullOrEmpty($uniqueName)) {
             throw new ApiError(500, sprintf("'shortName' attribute missing in ApiResource annotation of resource class '%s'", $resourceClass));
         } elseif (str_contains($uniqueName, '.') || str_contains($uniqueName, ',')) {
             throw new ApiError(500, sprintf("'shortName' attribute of resource class '%s' must not contain '.' or ',' characters: '%s'", $resourceClass, $uniqueName));