diff --git a/typo3/sysext/core/Classes/Routing/Aspect/PersistedAliasMapper.php b/typo3/sysext/core/Classes/Routing/Aspect/PersistedAliasMapper.php
index 9b049bfa86701bf83c33742ecf641d1ac23d4cbc..e0d23f6f6ca7fa66df0848a64926dbc4efc512e2 100644
--- a/typo3/sysext/core/Classes/Routing/Aspect/PersistedAliasMapper.php
+++ b/typo3/sysext/core/Classes/Routing/Aspect/PersistedAliasMapper.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Routing\Aspect;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\Connection;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Context\LanguageAspectFactory;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -23,7 +24,6 @@ use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
 use TYPO3\CMS\Core\Routing\Legacy\PersistedAliasMapperLegacyTrait;
 use TYPO3\CMS\Core\Site\SiteLanguageAwareInterface;
-use TYPO3\CMS\Core\Site\SiteLanguageAwareTrait;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -47,7 +47,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class PersistedAliasMapper implements PersistedMappableAspectInterface, StaticMappableAspectInterface, SiteLanguageAwareInterface
 {
-    use SiteLanguageAwareTrait;
+    use SiteLanguageAccessorTrait;
     use PersistedAliasMapperLegacyTrait;
 
     /**
@@ -196,16 +196,36 @@ class PersistedAliasMapper implements PersistedMappableAspectInterface, StaticMa
 
     protected function findByRouteFieldValue(string $value): ?array
     {
+        $languageAware = $this->languageFieldName !== null && $this->languageParentFieldName !== null;
+
         $queryBuilder = $this->createQueryBuilder();
-        $result = $queryBuilder
-            ->select(...$this->persistenceFieldNames)
-            ->where($queryBuilder->expr()->eq(
+        $constraints = [
+            $queryBuilder->expr()->eq(
                 $this->routeFieldName,
                 $queryBuilder->createNamedParameter($value, \PDO::PARAM_STR)
-            ))
+            ),
+        ];
+
+        $languageIds = null;
+        if ($languageAware) {
+            $languageIds = $this->resolveAllRelevantLanguageIds();
+            $constraints[] = $queryBuilder->expr()->in(
+                $this->languageFieldName,
+                $queryBuilder->createNamedParameter($languageIds, Connection::PARAM_INT_ARRAY)
+            );
+        }
+
+        $results = $queryBuilder
+            ->select(...$this->persistenceFieldNames)
+            ->where(...$constraints)
             ->execute()
-            ->fetch();
-        return $result !== false ? $result : null;
+            ->fetchAll();
+        // return first result record in case table is not language aware
+        if (!$languageAware) {
+            return $results[0] ?? null;
+        }
+        // post-process language fallbacks
+        return $this->resolveLanguageFallback($results, $this->languageFieldName, $languageIds);
     }
 
     protected function createQueryBuilder(): QueryBuilder
diff --git a/typo3/sysext/core/Classes/Routing/Aspect/PersistedPatternMapper.php b/typo3/sysext/core/Classes/Routing/Aspect/PersistedPatternMapper.php
index f0c5b22a811baee76d1bdab76380969928965d9c..0f1cfa3cc2036fafe59cee21a0baaa77aa5c61ff 100644
--- a/typo3/sysext/core/Classes/Routing/Aspect/PersistedPatternMapper.php
+++ b/typo3/sysext/core/Classes/Routing/Aspect/PersistedPatternMapper.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Routing\Aspect;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\Connection;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Context\LanguageAspectFactory;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -23,7 +24,6 @@ use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
 use TYPO3\CMS\Core\Routing\Legacy\PersistedPatternMapperLegacyTrait;
 use TYPO3\CMS\Core\Site\SiteLanguageAwareInterface;
-use TYPO3\CMS\Core\Site\SiteLanguageAwareTrait;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -50,7 +50,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class PersistedPatternMapper implements PersistedMappableAspectInterface, StaticMappableAspectInterface, SiteLanguageAwareInterface
 {
-    use SiteLanguageAwareTrait;
+    use SiteLanguageAccessorTrait;
     use PersistedPatternMapperLegacyTrait;
 
     protected const PATTERN_RESULT = '#\{(?P<fieldName>[^}]+)\}#';
@@ -80,6 +80,11 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
      */
     protected $routeFieldResultNames;
 
+    /**
+     * @var string|null
+     */
+    protected $languageFieldName;
+
     /**
      * @var string|null
      */
@@ -116,6 +121,7 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
         $this->routeFieldPattern = $routeFieldPattern;
         $this->routeFieldResult = $routeFieldResult;
         $this->routeFieldResultNames = $routeFieldResultNames['fieldName'] ?? [];
+        $this->languageFieldName = $GLOBALS['TCA'][$this->tableName]['ctrl']['languageField'] ?? null;
         $this->languageParentFieldName = $GLOBALS['TCA'][$this->tableName]['ctrl']['transOrigPointerField'] ?? null;
     }
 
@@ -204,13 +210,21 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
 
     protected function findByRouteFieldValues(array $values): ?array
     {
+        $languageAware = $this->languageFieldName !== null && $this->languageParentFieldName !== null;
+
         $queryBuilder = $this->createQueryBuilder();
-        $result = $queryBuilder
+        $results = $queryBuilder
             ->select('*')
             ->where(...$this->createRouteFieldConstraints($queryBuilder, $values))
             ->execute()
-            ->fetch();
-        return $result !== false ? $result : null;
+            ->fetchAll();
+        // return first result record in case table is not language aware
+        if (!$languageAware) {
+            return $results[0] ?? null;
+        }
+        // post-process language fallbacks
+        $languageIds = $this->resolveAllRelevantLanguageIds();
+        return $this->resolveLanguageFallback($results, $this->languageFieldName, $languageIds);
     }
 
     protected function createQueryBuilder(): QueryBuilder
@@ -227,7 +241,8 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
      */
     protected function createRouteFieldConstraints(QueryBuilder $queryBuilder, array $values): array
     {
-        $languageExpansion = $this->languageParentFieldName && isset($values['uid']);
+        $languageAware = $this->languageFieldName !== null && $this->languageParentFieldName !== null;
+        $languageExpansion = $languageAware && isset($values['uid']);
 
         $constraints = [];
         foreach ($values as $fieldName => $fieldValue) {
@@ -242,7 +257,7 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
                 )
             );
         }
-        // If requested, either match uid or language parent field value
+        // either match uid or language parent field value (for any language)
         if ($languageExpansion) {
             $idParameter = $queryBuilder->createNamedParameter(
                 $values['uid'],
@@ -252,6 +267,13 @@ class PersistedPatternMapper implements PersistedMappableAspectInterface, Static
                 $queryBuilder->expr()->eq('uid', $idParameter),
                 $queryBuilder->expr()->eq($this->languageParentFieldName, $idParameter)
             );
+        // otherwise - basically uid is not in pattern - restrict to languages and apply fallbacks
+        } elseif ($languageAware) {
+            $languageIds = $this->resolveAllRelevantLanguageIds();
+            $constraints[] = $queryBuilder->expr()->in(
+                $this->languageFieldName,
+                $queryBuilder->createNamedParameter($languageIds, Connection::PARAM_INT_ARRAY)
+            );
         }
 
         return $constraints;
diff --git a/typo3/sysext/core/Classes/Routing/Aspect/SiteLanguageAccessorTrait.php b/typo3/sysext/core/Classes/Routing/Aspect/SiteLanguageAccessorTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..afe3111b3376732f098fadf9f1cdc94d6e8a1eef
--- /dev/null
+++ b/typo3/sysext/core/Classes/Routing/Aspect/SiteLanguageAccessorTrait.php
@@ -0,0 +1,99 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Routing\Aspect;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Context\LanguageAspect;
+use TYPO3\CMS\Core\Context\LanguageAspectFactory;
+use TYPO3\CMS\Core\Site\SiteLanguageAwareTrait;
+use TYPO3\CMS\Core\Utility\MathUtility;
+
+trait SiteLanguageAccessorTrait
+{
+    use SiteLanguageAwareTrait;
+
+    /**
+     * @var LanguageAspect
+     */
+    protected $languageAspect;
+
+    /**
+     * Resolves one record out of given language fallbacks.
+     *
+     * @param array $results
+     * @param string|null $languageFieldName
+     * @param array|null $languageIds
+     * @return array|null
+     */
+    protected function resolveLanguageFallback(array $results, ?string $languageFieldName, ?array $languageIds): ?array
+    {
+        if ($results === []) {
+            return null;
+        }
+        if ($languageFieldName === null || $languageIds === null) {
+            return $results[0];
+        }
+        usort(
+            $results,
+            // orders records by there occurrence in $languageFallbackIds
+            function (array $a, array $b) use ($languageFieldName, $languageIds): int {
+                $languageA = (int)$a[$languageFieldName];
+                $languageB = (int)$b[$languageFieldName];
+                return array_search($languageA, $languageIds, true)
+                    - array_search($languageB, $languageIds, true);
+            }
+        );
+        return $results[0];
+    }
+
+    /**
+     * Resolves all language ids that are relevant to retrieve the most specific variant of a record.
+     * The order of these ids defines the processing order concerning language fallback - most specific
+     * language comes first in this array.
+     *
+     * + "all language (-1)", most specific if present since there cannot be any localizations
+     * + "current language" most specific for the current given request context
+     * + "language fallbacks" falling back to language alternatives (might include "default language")
+     *
+     * @return int[]
+     */
+    protected function resolveAllRelevantLanguageIds()
+    {
+        $languageIds = [-1, $this->siteLanguage->getLanguageId()];
+        foreach ($this->getLanguageAspect()->getFallbackChain() as $item) {
+            if (in_array($item, $languageIds, true) || !MathUtility::canBeInterpretedAsInteger($item)) {
+                continue;
+            }
+            $languageIds[] = (int)$item;
+        }
+        return $languageIds;
+    }
+
+    /**
+     * Provides LanguageAspect which contains the logic how fallbacks
+     * for a given context/overlay-mode shall be handled.
+     *
+     * @return LanguageAspect
+     * @see LanguageAspectFactory::createFromSiteLanguage
+     */
+    protected function getLanguageAspect(): LanguageAspect
+    {
+        if ($this->languageAspect === null) {
+            $this->languageAspect = LanguageAspectFactory::createFromSiteLanguage($this->siteLanguage);
+        }
+        return $this->languageAspect;
+    }
+}
diff --git a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
index c8d32b7b7b0a2506392f45e9749b0b5d27fac5fb..9224cd5f0151170c816bd10dfc8e28e1a8ef9f0c 100644
--- a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
+++ b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
@@ -112,28 +112,28 @@ class PersistedAliasMapperTest extends FunctionalTestCase
 
             '30xx-slug-fr-ca, fr-ca language' => ['30xx-slug-fr-ca', 'fr-ca', '3010'],
             // '30xx-slug-fr-ca' available in default language as well, fallbacks to that one
-            '30xx-slug-fr-ca, fr-fr language' => ['30xx-slug-fr-ca', 'fr-fr', '3010'],
+            '30xx-slug-fr-ca, fr-fr language' => ['30xx-slug-fr-ca', 'fr-fr', '3030'],
             // '30xx-slug-fr-ca' available in default language, use it directly
-            '30xx-slug-fr-ca, default language' => ['30xx-slug-fr-ca', 'default', '3010'],
+            '30xx-slug-fr-ca, default language' => ['30xx-slug-fr-ca', 'default', '3030'],
 
             '30xx-slug-fr, fr-ca language' => ['30xx-slug-fr', 'fr-ca', '3010'],
             '30xx-slug-fr, fr-fr language' => ['30xx-slug-fr', 'fr-fr', '3010'],
             // '30xx-slug-fr-ca' available in default language, use it directly
-            '30xx-slug-fr, default language' => ['30xx-slug-fr', 'default', '3010'],
+            '30xx-slug-fr, default language' => ['30xx-slug-fr', 'default', '3020'],
 
             // basically the same, but being stored in reverse order in database
             '40xx-slug, default language' => ['40xx-slug', 'default', '4040'],
             '40xx-slug, fr-fr language' => ['40xx-slug', 'fr-fr', '4040'],
             '40xx-slug, fr-ca language' => ['40xx-slug', 'fr-ca', '4040'],
 
-            '40xx-slug-fr-ca, fr-ca language' => ['40xx-slug-fr-ca', 'fr-ca', '4030'],
+            '40xx-slug-fr-ca, fr-ca language' => ['40xx-slug-fr-ca', 'fr-ca', '4040'],
             // '40xx-slug-fr-ca' available in default language as well, fallbacks to that one
             '40xx-slug-fr-ca, fr-fr language' => ['40xx-slug-fr-ca', 'fr-fr', '4030'],
             // '40xx-slug-fr-ca' available in default language, use it directly
             '40xx-slug-fr-ca, default language' => ['40xx-slug-fr-ca', 'default', '4030'],
 
-            '40xx-slug-fr, fr-ca language' => ['40xx-slug-fr', 'fr-ca', '4020'],
-            '40xx-slug-fr, fr-fr language' => ['40xx-slug-fr', 'fr-fr', '4020'],
+            '40xx-slug-fr, fr-ca language' => ['40xx-slug-fr', 'fr-ca', '4040'],
+            '40xx-slug-fr, fr-fr language' => ['40xx-slug-fr', 'fr-fr', '4040'],
             // '40xx-slug-fr-ca' available in default language, use it directly
             '40xx-slug-fr, default language' => ['40xx-slug-fr', 'default', '4020'],
         ];
@@ -146,7 +146,6 @@ class PersistedAliasMapperTest extends FunctionalTestCase
      *
      * @test
      * @dataProvider languageAwareRecordsAreResolvedDataProvider
-     * @group not-postgres
      */
     public function languageAwareRecordsAreResolved(string $requestValue, string $language, ?string $expectation): void
     {