diff --git a/typo3/sysext/install/Classes/Updates/RowUpdater/L10nModeUpdater.php b/typo3/sysext/install/Classes/Updates/RowUpdater/L10nModeUpdater.php
index 5d21dc566e0860bd221a5cb269987e15e57f905a..dadd54ed7caa68fecb73014b3244afd299d63087 100644
--- a/typo3/sysext/install/Classes/Updates/RowUpdater/L10nModeUpdater.php
+++ b/typo3/sysext/install/Classes/Updates/RowUpdater/L10nModeUpdater.php
@@ -18,7 +18,6 @@ namespace TYPO3\CMS\Install\Updates\RowUpdater;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
-use TYPO3\CMS\Core\DataHandling\Localization\DataMapProcessor;
 use TYPO3\CMS\Core\DataHandling\Localization\State;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -70,7 +69,7 @@ class L10nModeUpdater implements RowUpdaterInterface
      */
     public function updateTableRow(string $tableName, array $inputRow): array
     {
-        $currentId = $inputRow['uid'];
+        $currentId = (int)$inputRow['uid'];
 
         if (empty($this->payload[$tableName]['localizations'][$currentId])) {
             return $inputRow;
@@ -91,39 +90,21 @@ class L10nModeUpdater implements RowUpdaterInterface
         // the admin user is required to defined workspace state when working with DataHandler
         $fakeAdminUser = GeneralUtility::makeInstance(BackendUserAuthentication::class);
         $fakeAdminUser->user = ['uid' => 0, 'username' => '_migration_', 'admin' => 1];
-        $fakeAdminUser->workspace = ($inputRow['t3ver_wsid'] ?? 0);
+        $fakeAdminUser->workspace = (int)($inputRow['t3ver_wsid'] ?? 0);
         $GLOBALS['BE_USER'] = $fakeAdminUser;
 
         $tablePayload = $this->payload[$tableName];
-        $parentId = $tablePayload['localizations'][$currentId];
-        $parentTableName = ($tableName === 'pages_language_overlay' ? 'pages' : $tableName);
 
         $liveId = $currentId;
         if (!empty($inputRow['t3ver_wsid'])
             && !empty($inputRow['t3ver_oid'])
             && !VersionState::cast($inputRow['t3ver_state'])
                 ->equals(VersionState::NEW_PLACEHOLDER_VERSION)) {
-            $liveId = $inputRow['t3ver_oid'];
+            $liveId = (int)$inputRow['t3ver_oid'];
         }
 
         $dataMap = [];
 
-        // simulate modifying a parent record to trigger dependent updates
-        if (in_array('exclude', $tablePayload['fieldModes'])) {
-            $parentRecord = $this->getRow($parentTableName, $parentId);
-            foreach ($tablePayload['fieldModes'] as $fieldName => $fieldMode) {
-                if ($fieldMode !== 'exclude') {
-                    continue;
-                }
-                $dataMap[$parentTableName][$parentId][$fieldName] = $parentRecord[$fieldName];
-            }
-            $dataMap = DataMapProcessor::instance($dataMap, $fakeAdminUser)->process();
-            unset($dataMap[$parentTableName][$parentId]);
-            if (empty($dataMap[$parentTableName])) {
-                unset($dataMap[$parentTableName]);
-            }
-        }
-
         // define localization states and thus trigger updates later
         if (State::isApplicable($tableName)) {
             $stateUpdates = [];
@@ -138,33 +119,38 @@ class L10nModeUpdater implements RowUpdaterInterface
                 }
             }
 
+            // fetch the language state upfront, so that calling DataMapProcessor below
+            // will handle mergeIfNotBlank fields properly
             $languageState = State::create($tableName);
             $languageState->update($stateUpdates);
-            // only consider field names that still used mergeIfNotBlank
-            $modifiedFieldNames = array_intersect(
-                array_keys($tablePayload['fieldModes']),
-                $languageState->getModifiedFieldNames()
-            );
-            if (!empty($modifiedFieldNames)) {
-                $dataMap = [
-                    $tableName => [
-                        $liveId => [
-                            'l10n_state' => $languageState->toArray()
-                        ]
+            $dataMap = [
+                $tableName => [
+                    $liveId => [
+                        'l10n_state' => $languageState->toArray()
                     ]
-                ];
-            }
+                ]
+            ];
         }
 
-        if (empty($dataMap)) {
-            return $inputRow;
+        // simulate modifying a parent record to trigger dependent updates
+        if (in_array('exclude', $tablePayload['fieldModes'], true)) {
+            $record = $this->getRow($tableName, $liveId);
+            foreach ($tablePayload['fieldModes'] as $fieldName => $fieldMode) {
+                if ($fieldMode !== 'exclude') {
+                    continue;
+                }
+                $dataMap[$tableName][$liveId][$fieldName] = $record[$fieldName];
+            }
         }
 
-        // let DataHandler process all updates, $inputRow won't change
-        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
-        $dataHandler->enableLogging = false;
-        $dataHandler->start($dataMap, [], $fakeAdminUser);
-        $dataHandler->process_datamap();
+        // in case $dataMap is empty, nothing has to be updated
+        if (!empty($dataMap)) {
+            // let DataHandler process all updates, $inputRow won't change
+            $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
+            $dataHandler->enableLogging = false;
+            $dataHandler->start($dataMap, [], $fakeAdminUser);
+            $dataHandler->process_datamap();
+        }
 
         if (!empty($dataHandlerHooks)) {
             $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php'] = $dataHandlerHooks;
diff --git a/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultElements.csv b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultElements.csv
new file mode 100644
index 0000000000000000000000000000000000000000..5e532ac6e9e54bd9c60f22504aaa72c5c1a42262
--- /dev/null
+++ b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultElements.csv
@@ -0,0 +1,29 @@
+"sys_language",,,,,,,,,,,,,,,,,,
+,"uid","pid","hidden","title","flag",,,,,,,,,,,,,
+,1,0,0,"Dansk","dk",,,,,,,,,,,,,
+,2,0,0,"Deutsch","de",,,,,,,,,,,,,
+"tt_content",,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","image","tx_irretutorial_1nff_hotels",,
+,297,89,256,0,0,0,0,0,0,0,0,0,"Regular Element #1",0,2,,
+,298,89,512,0,0,0,0,0,0,0,0,0,"Regular Element #2",0,0,,
+,299,89,1024,0,1,297,0,0,0,0,0,0,"",0,0,,
+,300,89,2048,0,1,298,0,0,0,0,0,0,"Regular Element #2++",0,1,,
+"tx_irretutorial_1nff_hotel",,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l18n_diffsource","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","parentid","parenttable","parentidentifier","offers"
+,2,89,1,0,0,0,,0,0,0,0,0,0,"Hotel #0",89,"pages",,0
+,3,89,1,0,0,0,,0,0,0,0,0,0,"Hotel #1",297,"tt_content",,2
+,4,89,2,0,0,0,,0,0,0,0,0,0,"Hotel #2",297,"tt_content",,1
+,5,89,1,0,1,0,,0,0,0,0,0,0,"Hotel #3",300,"tt_content",,0
+"tx_irretutorial_1nff_offer",,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l18n_diffsource","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","parentid","parenttable","parentidentifier","prices"
+,5,89,1,0,0,0,,0,0,0,0,0,0,"Offer #1.1",3,"tx_irretutorial_1nff_hotel",,3
+,6,89,2,0,0,0,,0,0,0,0,0,0,"Offer #1.2",3,"tx_irretutorial_1nff_hotel",,2
+,7,89,1,0,0,0,,0,0,0,0,0,0,"Offer #2.1",4,"tx_irretutorial_1nff_hotel",,1
+"tx_irretutorial_1nff_price",,,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l18n_diffsource","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","parentid","parenttable","parentidentifier",
+,7,89,1,0,0,0,,0,0,0,0,0,0,"Price #1.1.1",5,"tx_irretutorial_1nff_offer",,
+,8,89,2,0,0,0,,0,0,0,0,0,0,"Price #1.1.2",5,"tx_irretutorial_1nff_offer",,
+,9,89,3,0,0,0,,0,0,0,0,0,0,"Price #1.1.3",5,"tx_irretutorial_1nff_offer",,
+,10,89,1,0,0,0,,0,0,0,0,0,0,"Price #1.2.1",6,"tx_irretutorial_1nff_offer",,
+,11,89,2,0,0,0,,0,0,0,0,0,0,"Price #1.2.2",6,"tx_irretutorial_1nff_offer",,
+,12,89,1,0,0,0,,0,0,0,0,0,0,"Price #2.1.1",7,"tx_irretutorial_1nff_offer",,
diff --git a/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultPages.csv b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultPages.csv
new file mode 100644
index 0000000000000000000000000000000000000000..b40e9e357c374f89040906482da9a91b7aa310d3
--- /dev/null
+++ b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/LiveDefaultPages.csv
@@ -0,0 +1,6 @@
+"pages"
+,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title","tx_irretutorial_hotels"
+,1,0,256,0,0,0,0,0,0,0,"FunctionalTest",0
+,88,1,256,0,0,0,0,0,0,0,"DataHandlerTest",0
+,89,88,256,0,0,0,0,0,0,0,"Relations",1
+,90,88,512,0,0,0,0,0,0,0,"Target",0
diff --git a/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/recordsCanBeUpdated.csv b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/recordsCanBeUpdated.csv
new file mode 100644
index 0000000000000000000000000000000000000000..169b198410db7a7f4a2d7b4ff94ff5b7abb353e0
--- /dev/null
+++ b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/recordsCanBeUpdated.csv
@@ -0,0 +1,40 @@
+sys_language
+,uid,pid,hidden,title,flag
+,1,0,0,Dansk,dk
+,2,0,0,Deutsch,de
+tt_content
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,header,image,tx_irretutorial_1nff_hotels,l10n_state
+,297,89,256,0,0,0,0,0,0,0,0,0,"Regular Element #1",0,2,"\NULL"
+,298,89,512,0,0,0,0,0,0,0,0,0,"Regular Element #2",0,0,"\NULL"
+,299,89,1024,0,1,297,0,0,0,0,0,0,"Regular Element #1",0,2,"{""header"":""parent"",""tx_irretutorial_1nff_hotels"":""parent""}"
+,300,89,2048,0,1,298,0,0,0,0,0,0,"Regular Element #2++",0,1,"{""header"":""custom"",""tx_irretutorial_1nff_hotels"":""custom""}"
+tx_irretutorial_1nff_hotel
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l18n_diffsource,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,parentid,parenttable,parentidentifier,offers,l10n_state
+,2,89,512,0,0,0,,0,0,0,0,0,0,"Hotel #0",89,pages,,0,"\NULL"
+,3,89,768,0,0,0,,0,0,0,0,0,0,"Hotel #1",297,tt_content,,2,"\NULL"
+,4,89,1536,0,0,0,,0,0,0,0,0,0,"Hotel #2",297,tt_content,,1,"\NULL"
+,5,89,1280,0,1,0,,0,0,0,0,0,0,"Hotel #3",300,tt_content,,0,"\NULL"
+,6,89,1,0,1,3,,3,0,0,0,0,0,"[Translate to Dansk:] Hotel #1",299,tt_content,,2,"\NULL"
+,7,89,2,0,1,4,,4,0,0,0,0,0,"[Translate to Dansk:] Hotel #2",299,tt_content,,1,"\NULL"
+tx_irretutorial_1nff_offer
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l18n_diffsource,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,parentid,parenttable,parentidentifier,prices,l10n_state
+,5,89,1280,0,0,0,,0,0,0,0,0,0,"Offer #1.1",3,tx_irretutorial_1nff_hotel,,3,"\NULL"
+,6,89,1792,0,0,0,,0,0,0,0,0,0,"Offer #1.2",3,tx_irretutorial_1nff_hotel,,2,"\NULL"
+,7,89,1536,0,0,0,,0,0,0,0,0,0,"Offer #2.1",4,tx_irretutorial_1nff_hotel,,1,"\NULL"
+,8,89,512,0,1,5,,5,0,0,0,0,0,"[Translate to Dansk:] Offer #1.1",6,tx_irretutorial_1nff_hotel,,3,"\NULL"
+,9,89,1024,0,1,6,,6,0,0,0,0,0,"[Translate to Dansk:] Offer #1.2",6,tx_irretutorial_1nff_hotel,,2,"\NULL"
+,10,89,1,0,1,7,,7,0,0,0,0,0,"[Translate to Dansk:] Offer #2.1",7,tx_irretutorial_1nff_hotel,,1,"\NULL"
+tx_irretutorial_1nff_price
+,uid,pid,sorting,deleted,sys_language_uid,l18n_parent,l18n_diffsource,t3_origuid,t3ver_wsid,t3ver_state,t3ver_stage,t3ver_oid,t3ver_move_id,title,parentid,parenttable,parentidentifier,l10n_state
+,7,89,2048,0,0,0,,0,0,0,0,0,0,"Price #1.1.1",5,tx_irretutorial_1nff_offer,,"\NULL"
+,8,89,2816,0,0,0,,0,0,0,0,0,0,"Price #1.1.2",5,tx_irretutorial_1nff_offer,,"\NULL"
+,9,89,3328,0,0,0,,0,0,0,0,0,0,"Price #1.1.3",5,tx_irretutorial_1nff_offer,,"\NULL"
+,10,89,2304,0,0,0,,0,0,0,0,0,0,"Price #1.2.1",6,tx_irretutorial_1nff_offer,,"\NULL"
+,11,89,3072,0,0,0,,0,0,0,0,0,0,"Price #1.2.2",6,tx_irretutorial_1nff_offer,,"\NULL"
+,12,89,2560,0,0,0,,0,0,0,0,0,0,"Price #2.1.1",7,tx_irretutorial_1nff_offer,,"\NULL"
+,13,89,1280,0,1,7,,7,0,0,0,0,0,"[Translate to Dansk:] Price #1.1.1",8,tx_irretutorial_1nff_offer,,"\NULL"
+,14,89,1536,0,1,8,,8,0,0,0,0,0,"[Translate to Dansk:] Price #1.1.2",8,tx_irretutorial_1nff_offer,,"\NULL"
+,15,89,1792,0,1,9,,9,0,0,0,0,0,"[Translate to Dansk:] Price #1.1.3",8,tx_irretutorial_1nff_offer,,"\NULL"
+,16,89,512,0,1,10,,10,0,0,0,0,0,"[Translate to Dansk:] Price #1.2.1",9,tx_irretutorial_1nff_offer,,"\NULL"
+,17,89,1024,0,1,11,,11,0,0,0,0,0,"[Translate to Dansk:] Price #1.2.2",9,tx_irretutorial_1nff_offer,,"\NULL"
+,18,89,1,0,1,12,,12,0,0,0,0,0,"[Translate to Dansk:] Price #2.1.1",10,tx_irretutorial_1nff_offer,,"\NULL"
diff --git a/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/L10nModeUpdaterTest.php b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/L10nModeUpdaterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8a2d7d1ec32bb6546d3232dda4ef77fe7f439ef
--- /dev/null
+++ b/typo3/sysext/install/Tests/Functional/Updates/RowUpdater/L10nModeUpdaterTest.php
@@ -0,0 +1,101 @@
+<?php
+namespace TYPO3\CMS\Install\Tests\Functional\Updates\RowUpdater;
+
+/*
+ * 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\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Updates\RowUpdater\L10nModeUpdater;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+/**
+ * Test Class for L10nModeUpdater
+ */
+class L10nModeUpdaterTest extends FunctionalTestCase
+{
+    /**
+     * @var string
+     */
+    protected $scenarioDataSetDirectory = 'typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/';
+
+    /**
+     * @var string
+     */
+    protected $assertionDataSetDirectory = 'typo3/sysext/install/Tests/Functional/Updates/RowUpdater/DataSet/';
+
+    /**
+     * @var string[]
+     */
+    protected $coreExtensionsToLoad = [
+        'workspaces',
+    ];
+
+    /**
+     * @var string[]
+     */
+    protected $testExtensionsToLoad = [
+        'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/irre_tutorial',
+    ];
+
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->importScenarioDataSet('LiveDefaultPages');
+        $this->importScenarioDataSet('LiveDefaultElements');
+
+        $GLOBALS['TCA']['tt_content']['columns']['image']['l10n_mode'] = 'exclude';
+        $GLOBALS['TCA']['tt_content']['columns']['header']['config']['behaviour']['allowLanguageSynchronization'] = true;
+        $GLOBALS['TCA']['tt_content']['columns']['tx_irretutorial_1nff_hotels']['config']['behaviour']['allowLanguageSynchronization'] = true;
+    }
+
+    /**
+     * @param string $dataSetName
+     */
+    protected function importScenarioDataSet($dataSetName)
+    {
+        $fileName = rtrim($this->scenarioDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
+        $fileName = GeneralUtility::getFileAbsFileName($fileName);
+        $this->importCSVDataSet($fileName);
+    }
+
+    protected function assertAssertionDataSet($dataSetName)
+    {
+        $fileName = rtrim($this->assertionDataSetDirectory, '/') . '/' . $dataSetName . '.csv';
+        $fileName = GeneralUtility::getFileAbsFileName($fileName);
+        $this->assertCSVDataSet($fileName);
+    }
+
+    /**
+     * @return array
+     */
+    protected function getTableNames(): array
+    {
+        return array_keys($GLOBALS['TCA']);
+    }
+
+    /**
+     * @test
+     */
+    public function recordsCanBeUpdated()
+    {
+        $updater = new L10nModeUpdater();
+        foreach ($this->getTableNames() as $tableName) {
+            $updater->hasPotentialUpdateForTable($tableName);
+            foreach ($this->getAllRecords($tableName) as $record) {
+                $updater->updateTableRow($tableName, $record);
+            }
+        }
+
+        $this->assertAssertionDataSet('recordsCanBeUpdated');
+    }
+}