diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index fff706a18a1d9d5a5b696154ea54747eb584d946..d83d8e31d5fefaf2dcd610cf0f30a92e81f25ed2 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -5703,7 +5703,7 @@ class DataHandler implements LoggerAwareInterface
                     }
                 }
             } elseif ($this->isReferenceField($fieldConfig) && !empty($fieldConfig['MM'])) {
-                $this->discardMmRelations($fieldConfig, $record);
+                $this->discardMmRelations($table, $fieldConfig, $record);
             }
             // @todo not inline and not mm - probably not handled correctly and has no proper test coverage yet
         }
@@ -5713,10 +5713,11 @@ class DataHandler implements LoggerAwareInterface
      * When a workspace record row is discarded that has mm relations, existing mm table rows need
      * to be deleted. The method performs the delete operation depending on TCA field configuration.
      *
+     * @param string $table Table name of this record
      * @param array $fieldConfig TCA configuration of this field
      * @param array $record The full record of a left- or ride-side relation
      */
-    protected function discardMmRelations(array $fieldConfig, array $record): void
+    protected function discardMmRelations(string $table, array $fieldConfig, array $record): void
     {
         $recordUid = (int)$record['uid'];
         $mmTableName = $fieldConfig['MM'];
@@ -5745,6 +5746,14 @@ class DataHandler implements LoggerAwareInterface
             );
         }
         $queryBuilder->execute();
+
+        // refindex treatment for mm relation handling: If the to discard record is foreign side of an mm relation,
+        // there may be other refindex rows that become obsolete when that record is discarded. See Modify
+        // addCategoryRelation sys_category-29->tt_content-298. We thus register an update for references
+        // to this item (right side - ref_table, ref_uid) in reference index updater to catch these.
+        if ($relationUidFieldName === 'uid_foreign') {
+            $this->referenceIndexUpdater->registerUpdateForReferencesToItem($table, $recordUid, (int)$record['t3ver_wsid']);
+        }
     }
 
     /**
@@ -5877,7 +5886,7 @@ class DataHandler implements LoggerAwareInterface
      *
      * @internal should only be used from within DataHandler
      */
-    public function versionPublishManyToManyRelations(string $table, array $liveRecord, array $workspaceRecord): void
+    public function versionPublishManyToManyRelations(string $table, array $liveRecord, array $workspaceRecord, int $fromWorkspace): void
     {
         if (!is_array($GLOBALS['TCA'][$table]['columns'])) {
             return;
@@ -5938,7 +5947,8 @@ class DataHandler implements LoggerAwareInterface
 
         // Update mm table relations of workspace record to uid of live record
         foreach ($toUpdateRegistry as $config) {
-            $uidFieldName = $this->mmRelationIsLocalSide($config) ? 'uid_local' : 'uid_foreign';
+            $mmRelationIsLocalSide = $this->mmRelationIsLocalSide($config);
+            $uidFieldName = $mmRelationIsLocalSide ? 'uid_local' : 'uid_foreign';
             $mmTableName = $config['MM'];
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($mmTableName);
             $queryBuilder->update($mmTableName);
@@ -5954,6 +5964,17 @@ class DataHandler implements LoggerAwareInterface
                 ));
             }
             $queryBuilder->execute();
+
+            if (!$mmRelationIsLocalSide) {
+                // refindex treatment for mm relation handling: If the to publish record is foreign side of an mm relation, we need
+                // to instruct refindex updater to update all local side references for the live record the current workspace record
+                // has on foreign side. See ManyToMany Publish addCategoryRelation, this will create the sys_category-31->tt_content-297 entry.
+                $this->referenceIndexUpdater->registerUpdateForReferencesToItem($table, (int)$workspaceRecord['uid'], $fromWorkspace, 0);
+                // Similar, when in mm foreign side and relations are deleted in live during publish, other relations pointing to the
+                // same local side record may need updates due to different sorting, and the former refindex entry of the live record
+                // needs updates. See ManyToMany Publish deleteCategoryRelation scenario.
+                $this->referenceIndexUpdater->registerUpdateForReferencesToItem($table, (int)$liveRecord['uid'], 0);
+            }
         }
     }
 
@@ -7452,12 +7473,24 @@ class DataHandler implements LoggerAwareInterface
      * @param string $table Table name, used as tablename and ref_table
      * @param int $uid Record uid, used as recuid and ref_uid
      * @param int $workspace Workspace the record lives in
+     * @internal should only be used from within DataHandler
      */
     public function registerReferenceIndexRowsForDrop(string $table, int $uid, int $workspace): void
     {
         $this->referenceIndexUpdater->registerForDrop($table, $uid, $workspace);
     }
 
+    /**
+     * Helper method to access referenceIndexUpdater->registerUpdateForReferencesToItem()
+     * from within workspace DataHandlerHook.
+     *
+     * @internal Exists only for workspace DataHandlerHook. May vanish any time.
+     */
+    public function registerReferenceIndexUpdateForReferencesToItem(string $table, int $uid, int $workspace, int $targetWorkspace = null): void
+    {
+        $this->referenceIndexUpdater->registerUpdateForReferencesToItem($table, $uid, $workspace, $targetWorkspace);
+    }
+
     /*********************************************
      *
      * Misc functions
diff --git a/typo3/sysext/core/Classes/DataHandling/ReferenceIndexUpdater.php b/typo3/sysext/core/Classes/DataHandling/ReferenceIndexUpdater.php
index 36a5286e39f666afdc0eb00b636f35ce7a98623c..d3f61710a853552948d9a8192c16834e0f2c4e59 100644
--- a/typo3/sysext/core/Classes/DataHandling/ReferenceIndexUpdater.php
+++ b/typo3/sysext/core/Classes/DataHandling/ReferenceIndexUpdater.php
@@ -82,13 +82,13 @@ class ReferenceIndexUpdater
     /**
      * Find reference index rows pointing to given table/uid combination and register them for update. Important in
      * delete and publish scenarios where a child is deleted to make sure any references to this child are dropped, too.
-     * In publish scenarios reference index may exist for a non live workspace, but should be updated for live workspace.
+     * In publish scenarios reference index may exist for a non-live workspace, but should be updated for live workspace.
      * The optional $targetWorkspace argument is used for this.
      *
      * @param string $table Table name, used as ref_table
      * @param int $uid Record uid, used as ref_uid
      * @param int $workspace The workspace given record lives in
-     * @param int $targetWorkspace The target workspace the record has been swapped to
+     * @param int|null $targetWorkspace The target workspace the record has been swapped to
      */
     public function registerUpdateForReferencesToItem(string $table, int $uid, int $workspace, int $targetWorkspace = null): void
     {
diff --git a/typo3/sysext/core/Classes/Database/ReferenceIndex.php b/typo3/sysext/core/Classes/Database/ReferenceIndex.php
index 5539abc4fb64c356dc8284841c1e492653db758f..d65d56024ddd335b729946bb61612e7da72955c0 100644
--- a/typo3/sysext/core/Classes/Database/ReferenceIndex.php
+++ b/typo3/sysext/core/Classes/Database/ReferenceIndex.php
@@ -24,25 +24,19 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\ProgressListenerInterface;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
 use TYPO3\CMS\Core\Database\Platform\PlatformInformation;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
 use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
 use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory;
 use TYPO3\CMS\Core\Registry;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Reference index processing and relation extraction
  *
- * NOTICE: When the reference index is updated for an offline version the results may not be correct.
- * First, lets assumed that the reference update happens in LIVE workspace (ALWAYS update from Live workspace if you analyze whole database!)
- * Secondly, lets assume that in a Draft workspace you have changed the data structure of a parent page record - this is (in TemplaVoila) inherited by subpages.
- * When in the LIVE workspace the data structure for the records/pages in the offline workspace will not be evaluated to the right one simply because the data
- * structure is taken from a rootline traversal and in the Live workspace that will NOT include the changed DataStructure! Thus the evaluation will be based
- * on the Data Structure set in the Live workspace!
- * Somehow this scenario is rarely going to happen. Yet, it is an inconsistency and I see now practical way to handle it - other than simply ignoring
- * maintaining the index for workspace records. Or we can say that the index is precise for all Live elements while glitches might happen in an offline workspace?
- * Anyway, I just wanted to document this finding - I don't think we can find a solution for it. And its very TemplaVoila specific.
+ * @internal Extensions shouldn't fiddle with the reference index themselves, it's task of DataHandler to do this.
  */
 class ReferenceIndex implements LoggerAwareInterface
 {
@@ -359,11 +353,13 @@ class ReferenceIndex implements LoggerAwareInterface
      */
     protected function createEntryDataUsingRecord(string $tableName, array $record, string $fieldName, string $flexPointer, string $referencedTable, int $referencedUid, string $referenceString = '', int $sort = -1, string $softReferenceKey = '', string $softReferenceId = '')
     {
-        $workspaceId = 0;
+        $currentWorkspace = $this->getWorkspaceId();
         if (BackendUtility::isTableWorkspaceEnabled($tableName)) {
-            $workspaceId = $this->getWorkspaceId();
-            if (isset($record['t3ver_wsid']) && (int)$record['t3ver_wsid'] !== $workspaceId) {
-                // The given record is workspace-enabled but doesn't live in the selected workspace => don't add index as it's not actually there
+            $fieldConfig = $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config'];
+            if (isset($record['t3ver_wsid']) && (int)$record['t3ver_wsid'] !== $currentWorkspace && empty($fieldConfig['MM'])) {
+                // The given record is workspace-enabled but doesn't live in the selected workspace. Don't add index, it's not actually there.
+                // We still add those rows if the record is a local side live record of an MM relation and can be a target of a workspace record.
+                // See workspaces ManyToMany Modify addCategoryRelation for details on this case.
                 return false;
             }
         }
@@ -375,7 +371,7 @@ class ReferenceIndex implements LoggerAwareInterface
             'softref_key' => $softReferenceKey,
             'softref_id' => $softReferenceId,
             'sorting' => $sort,
-            'workspace' => $workspaceId,
+            'workspace' => $currentWorkspace,
             'ref_table' => $referencedTable,
             'ref_uid' => $referencedUid,
             'ref_string' => mb_substr($referenceString, 0, 1024),
@@ -458,7 +454,7 @@ class ReferenceIndex implements LoggerAwareInterface
                     $conf['softref'] = 'typolink';
                 }
                 // Add DB:
-                $resultsFromDatabase = $this->getRelations_procDB($value, $conf, $uid, $table);
+                $resultsFromDatabase = $this->getRelations_procDB($value, $conf, $uid, $table, $row);
                 if (!empty($resultsFromDatabase)) {
                     // Create an entry for the field with all DB relations:
                     $outRow[$field] = [
@@ -567,9 +563,10 @@ class ReferenceIndex implements LoggerAwareInterface
      * @param array $conf Field configuration array of type "TCA/columns
      * @param int $uid Field uid
      * @param string $table Table name
+     * @param array $row
      * @return array|bool If field type is OK it will return an array with the database relations. Else FALSE
      */
-    protected function getRelations_procDB($value, $conf, $uid, $table = '')
+    protected function getRelations_procDB($value, $conf, $uid, $table = '', array $row = [])
     {
         // Get IRRE relations
         if (empty($conf)) {
@@ -586,11 +583,36 @@ class ReferenceIndex implements LoggerAwareInterface
         if ($this->isDbReferenceField($conf)) {
             $allowedTables = $conf['type'] === 'group' ? $conf['allowed'] : $conf['foreign_table'];
             if ($conf['MM_opposite_field'] ?? false) {
+                // Never handle sys_refindex when looking at MM from foreign side
                 return [];
             }
+
             $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
+            $dbAnalysis->setWorkspaceId($this->getWorkspaceId());
             $dbAnalysis->start($value, $allowedTables, $conf['MM'] ?? '', $uid, $table, $conf);
-            return $dbAnalysis->itemArray;
+            $itemArray = $dbAnalysis->itemArray;
+
+            if (ExtensionManagementUtility::isLoaded('workspaces')
+                && $this->getWorkspaceId() > 0
+                && !empty($conf['MM'] ?? '')
+                && !empty($conf['allowed'] ?? '')
+                && empty($conf['MM_opposite_field'] ?? '')
+                && (int)($row['t3ver_wsid'] ?? 0) === 0
+            ) {
+                // When dealing with local side mm relations in workspace 0, there may be workspace records on the foreign
+                // side, for instance when those got an additional category. See ManyToMany Modify addCategoryRelations test.
+                // In those cases, the full set of relations must be written to sys_refindex as workspace rows.
+                // But, if the relations in this workspace and live are identical, no sys_refindex workspace rows
+                // have to be added.
+                $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
+                $dbAnalysis->setWorkspaceId(0);
+                $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
+                $itemArrayLive = $dbAnalysis->itemArray;
+                if ($itemArrayLive === $itemArray) {
+                    $itemArray = false;
+                }
+            }
+            return $itemArray;
         }
         return false;
     }
@@ -890,18 +912,34 @@ class ReferenceIndex implements LoggerAwareInterface
      * @param bool $testOnly If set, only a test
      * @param ProgressListenerInterface|null $progressListener If set, the current progress is added to the listener
      * @return array Header and body status content
+     * @todo: Consider moving this together with the helper methods to a dedicated class.
      */
     public function updateIndex($testOnly, ?ProgressListenerInterface $progressListener = null)
     {
         $errors = [];
         $tableNames = [];
         $recCount = 0;
-        // Traverse all tables:
+        $isWorkspacesLoaded = ExtensionManagementUtility::isLoaded('workspaces');
         $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
         $refIndexConnectionName = empty($GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping']['sys_refindex'])
                 ? ConnectionPool::DEFAULT_CONNECTION_NAME
                 : $GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping']['sys_refindex'];
 
+        // Drop sys_refindex rows from deleted workspaces
+        $listOfActiveWorkspaces = $this->getListOfActiveWorkspaces();
+        $unusedWorkspaceRows = $this->getAmountOfUnusedWorkspaceRowsInReferenceIndex($listOfActiveWorkspaces);
+        if ($unusedWorkspaceRows > 0) {
+            $error = 'Index table hosted ' . $unusedWorkspaceRows . ' indexes for non-existing or deleted workspaces, now removed.';
+            $errors[] = $error;
+            if ($progressListener) {
+                $progressListener->log($error, LogLevel::WARNING);
+            }
+            if (!$testOnly) {
+                $this->removeUnusedWorkspaceRowsFromReferenceIndex($listOfActiveWorkspaces);
+            }
+        }
+
+        // Main loop traverses all records of all TCA tables
         foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
             if ($this->shouldExcludeTableFromReferenceIndex($tableName)) {
                 continue;
@@ -910,6 +948,18 @@ class ReferenceIndex implements LoggerAwareInterface
                 ? ConnectionPool::DEFAULT_CONNECTION_NAME
                 : $GLOBALS['TYPO3_CONF_VARS']['DB']['TableMapping'][$tableName];
 
+            // Some additional magic is needed if the table has a field that is the local side of
+            // a mm relation. See the variable usage below for details.
+            $tableHasLocalSideMmRelation = false;
+            foreach (($cfg['columns'] ?? []) as $fieldConfig) {
+                if (!empty($fieldConfig['config']['MM'] ?? '')
+                    && !empty($fieldConfig['config']['allowed'] ?? '')
+                    && empty($fieldConfig['config']['MM_opposite_field'] ?? '')
+                ) {
+                    $tableHasLocalSideMmRelation = true;
+                }
+            }
+
             $fields = ['uid'];
             if (BackendUtility::isTableWorkspaceEnabled($tableName)) {
                 $fields[] = 't3ver_wsid';
@@ -940,18 +990,38 @@ class ReferenceIndex implements LoggerAwareInterface
                 if ($progressListener) {
                     $progressListener->advance();
                 }
-                /** @var ReferenceIndex $refIndexObj */
-                $refIndexObj = GeneralUtility::makeInstance(self::class);
-                if (isset($record['t3ver_wsid'])) {
-                    $refIndexObj->setWorkspaceId($record['t3ver_wsid']);
-                }
-                $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $testOnly);
-                $recCount++;
-                if ($result['addedNodes'] || $result['deletedNodes']) {
-                    $error = 'Record ' . $tableName . ':' . $record['uid'] . ' had ' . $result['addedNodes'] . ' added indexes and ' . $result['deletedNodes'] . ' deleted indexes';
-                    $errors[] = $error;
-                    if ($progressListener) {
-                        $progressListener->log($error, LogLevel::WARNING);
+
+                if ($isWorkspacesLoaded && $tableHasLocalSideMmRelation && (int)($record['t3ver_wsid'] ?? 0) === 0) {
+                    // If we have record that can be the local side of a workspace relation, workspace records
+                    // may point to it, even though the record has no workspace overlay. See workspace ManyToMany
+                    // Modify addCategoryRelation as example. In those cases, we need to iterate all active workspaces
+                    // and update refindex for all foreign workspace records that point to it.
+                    foreach ($listOfActiveWorkspaces as $workspaceId) {
+                        $refIndexObj = GeneralUtility::makeInstance(self::class);
+                        $refIndexObj->setWorkspaceId($workspaceId);
+                        $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $testOnly);
+                        $recCount++;
+                        if ($result['addedNodes'] || $result['deletedNodes']) {
+                            $error = 'Record ' . $tableName . ':' . $record['uid'] . ' had ' . $result['addedNodes'] . ' added indexes and ' . $result['deletedNodes'] . ' deleted indexes';
+                            $errors[] = $error;
+                            if ($progressListener) {
+                                $progressListener->log($error, LogLevel::WARNING);
+                            }
+                        }
+                    }
+                } else {
+                    $refIndexObj = GeneralUtility::makeInstance(self::class);
+                    if (isset($record['t3ver_wsid'])) {
+                        $refIndexObj->setWorkspaceId($record['t3ver_wsid']);
+                    }
+                    $result = $refIndexObj->updateRefIndexTable($tableName, $record['uid'], $testOnly);
+                    $recCount++;
+                    if ($result['addedNodes'] || $result['deletedNodes']) {
+                        $error = 'Record ' . $tableName . ':' . $record['uid'] . ' had ' . $result['addedNodes'] . ' added indexes and ' . $result['deletedNodes'] . ' deleted indexes';
+                        $errors[] = $error;
+                        if ($progressListener) {
+                            $progressListener->log($error, LogLevel::WARNING);
+                        }
                     }
                 }
             }
@@ -960,6 +1030,13 @@ class ReferenceIndex implements LoggerAwareInterface
             }
 
             // Subselect based queries only work on the same connection
+            // @todo: Consider dropping this in v12 and always use sub select: The base set of tables should
+            //        be in exactly one DB and only tables like caches should be "extractable" to a different DB?!
+            //        Even though sys_refindex is a "cache-like" table since it only holds secondary information that
+            //        can always be re-created by analyzing the entire data set, it shouldn't be possible to run it
+            //        on a different database since that prevents quick joins between sys_refindex and target relations.
+            //        We should probably have some report and/or install tool check to make sure all main tables
+            //        are on the same connection in v12.
             if ($refIndexConnectionName !== $tableConnectionName) {
                 $this->logger->error('Not checking table {table_name} for lost indexes, "sys_refindex" table uses a different connection', ['table_name' => $tableName]);
                 continue;
@@ -1017,6 +1094,8 @@ class ReferenceIndex implements LoggerAwareInterface
         }
 
         // Searching lost indexes for non-existing tables
+        // @todo: Consider moving this *before* the main re-index logic to have a smaller
+        //        dataset when starting with heavy lifting.
         $lostTables = $this->getAmountOfUnusedTablesInReferenceIndex($tableNames);
         if ($lostTables > 0) {
             $error = 'Index table hosted ' . $lostTables . ' indexes for non-existing tables, now removed';
@@ -1044,6 +1123,69 @@ class ReferenceIndex implements LoggerAwareInterface
         return ['resultText' => trim($recordsCheckedString), 'errors' => $errors];
     }
 
+    /**
+     * Helper method of updateIndex().
+     * Create list of non-deleted "active" workspace uid's. This contains at least 0 "live workspace".
+     *
+     * @return int[]
+     */
+    private function getListOfActiveWorkspaces(): array
+    {
+        if (!ExtensionManagementUtility::isLoaded('workspaces')) {
+            // If ext:workspaces is not loaded, "0" is the only valid one.
+            return [0];
+        }
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_workspace');
+        // There are no "hidden" workspaces, which wouldn't make much sense anyways.
+        $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+        $result = $queryBuilder->select('uid')->from('sys_workspace')->orderBy('uid')->execute();
+        // "0", plus non-deleted workspaces are active
+        $activeWorkspaces = [0];
+        while ($row = $result->fetchFirstColumn()) {
+            $activeWorkspaces[] = (int)$row[0];
+        }
+        return $activeWorkspaces;
+    }
+
+    /**
+     * Helper method of updateIndex() to find number of rows in sys_refindex that
+     * relate to a non-existing or deleted workspace record, even if workspaces is
+     * not loaded at all, but has been loaded somewhere in the past and sys_refindex
+     * rows have been created.
+     */
+    private function getAmountOfUnusedWorkspaceRowsInReferenceIndex(array $activeWorkspaces): int
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
+        $numberOfInvalidWorkspaceRecords = $queryBuilder->count('hash')
+            ->from('sys_refindex')
+            ->where(
+                $queryBuilder->expr()->notIn(
+                    'workspace',
+                    $queryBuilder->createNamedParameter($activeWorkspaces, Connection::PARAM_INT_ARRAY)
+                )
+            )
+            ->execute()
+            ->fetchOne();
+        return (int)$numberOfInvalidWorkspaceRecords;
+    }
+
+    /**
+     * Pair method of getAmountOfUnusedWorkspaceRowsInReferenceIndex() to actually delete
+     * sys_refindex rows of deleted workspace records, or all if ext:workspace is not loaded.
+     */
+    private function removeUnusedWorkspaceRowsFromReferenceIndex(array $activeWorkspaces): void
+    {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
+        $queryBuilder->delete('sys_refindex')
+            ->where(
+                $queryBuilder->expr()->notIn(
+                    'workspace',
+                    $queryBuilder->createNamedParameter($activeWorkspaces, Connection::PARAM_INT_ARRAY)
+                )
+            )
+            ->execute();
+    }
+
     protected function getAmountOfUnusedTablesInReferenceIndex(array $tableNames): int
     {
         $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
diff --git a/typo3/sysext/core/Classes/Database/RelationHandler.php b/typo3/sysext/core/Classes/Database/RelationHandler.php
index 6866abfd0aa008a1673a9fa7bc36d48e7770f193..3b2774b44b7d944dca3af789466b57c739d3971e 100644
--- a/typo3/sysext/core/Classes/Database/RelationHandler.php
+++ b/typo3/sysext/core/Classes/Database/RelationHandler.php
@@ -512,6 +512,11 @@ class RelationHandler
     /**
      * Reads the record tablename/id into the internal arrays itemArray and tableArray from MM records.
      *
+     * @todo: The source record is not checked for correct workspace. Say there is a category 5 in
+     *        workspace 1. setWorkspace(0) is called, after that readMM('sys_category_record_mm', 5 ...).
+     *        readMM will *still* return the list of records connected to this workspace 1 item,
+     *        even though workspace 0 has been set.
+     *
      * @param string $tableName MM Tablename
      * @param int|string $uid Local UID
      * @param string $mmOppositeTable Opposite table name
@@ -1377,8 +1382,15 @@ class RelationHandler
     }
 
     /**
+     * @todo: It *should* be possible to drop all three 'purge' methods by using
+     *        a clever join within readMM - that sounds doable now with pid -1 and
+     *        ws-pair records being gone since v11. It would resolve this indirect
+     *        callback logic and would reduce some queries. The (workspace) mm tests
+     *        should be complete enough now to verify if a change like that would do.
+     *
      * @param int|null $workspaceId
      * @return bool Whether items have been purged
+     * @internal
      */
     public function purgeItemArray($workspaceId = null)
     {
@@ -1470,7 +1482,7 @@ class RelationHandler
                 ->from($tableName)
                 ->where(
                     $queryBuilder->expr()->in(
-                        't3ver_oid',
+                        'uid',
                         $queryBuilder->createNamedParameter($chunk, Connection::PARAM_INT_ARRAY)
                     ),
                     $queryBuilder->expr()->neq(
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv b/typo3/sysext/core/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
index f95798989d9a64a9b0f3245b3741beb2d8827f88..af81ce46e96065441eb8d5ffd25f49ba0cd0b7b6 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
@@ -26,6 +26,7 @@
 ,298,89,512,0,0,0,0,0,0,0,0,"Regular Element #2",0,2
 "sys_refindex",,,,,,,,,,,,,,
 ,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,
+# @todo: Broken. Both 28->297 and 29->297 have sorting 0 here and in mm table ... sys_refindex has no sorting_foreign
 ,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceImport.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceImport.csv
new file mode 100644
index 0000000000000000000000000000000000000000..21e2abc22467e1d9d2b0cd68f26fdb32af301995
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceImport.csv
@@ -0,0 +1,16 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","tx_testirreforeignfield_hotels",,,,,,
+,1,0,256,0,0,0,0,0,0,"FunctionalTest",0,,,,,,
+,88,1,256,0,0,0,0,0,0,"DataHandlerTest",0,,,,,,
+,89,88,256,0,0,0,0,0,0,"Relations",1,,,,,,
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","tx_testirreforeignfield_hotels",,,
+,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",0,1,,,
+"tx_testirreforeignfield_hotel",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l18n_diffsource","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","offers"
+,3,89,1,0,0,0,,0,0,0,0,0,"Hotel #1",297,"tt_content","1nff.hotels",0
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+,"b9be8f0166b062001c138957270e72e2","tt_content",297,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",3,,,,,,
+# workspace extension not loaded - ws 1 entry should be removed
+,"iShouldBeRemoved1c138957270e72e2","tt_content",297,"tx_testirreforeignfield_hotels",,,,0,1,"tx_testirreforeignfield_hotel",3,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceResult.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceResult.csv
new file mode 100644
index 0000000000000000000000000000000000000000..45ec68ee26af7033a53d3e9ce8b4b7c4d383a397
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceResult.csv
@@ -0,0 +1,14 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","tx_testirreforeignfield_hotels",,,,,,
+,1,0,256,0,0,0,0,0,0,"FunctionalTest",0,,,,,,
+,88,1,256,0,0,0,0,0,0,"DataHandlerTest",0,,,,,,
+,89,88,256,0,0,0,0,0,0,"Relations",1,,,,,,
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","tx_testirreforeignfield_hotels",,,
+,297,89,256,0,0,0,0,0,0,0,0,"Regular Element #1",0,1,,,
+"tx_testirreforeignfield_hotel",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","l18n_diffsource","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","offers"
+,3,89,1,0,0,0,,0,0,0,0,0,"Hotel #1",297,"tt_content","1nff.hotels",0
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+,"b9be8f0166b062001c138957270e72e2","tt_content",297,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",3,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordImport.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordImport.csv
new file mode 100644
index 0000000000000000000000000000000000000000..ba2ce982ec4d355b80d887e9893c787482de81b5
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordImport.csv
@@ -0,0 +1,32 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title",,,,,,,,
+,1,0,256,0,0,0,0,0,"FunctionalTest",,,,,,,,
+,88,1,256,0,0,0,0,0,"DataHandlerTest",,,,,,,,
+,89,88,256,0,0,0,0,0,"Relations",,,,,,,,
+"sys_workspace",,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","title","adminusers","members","db_mountpoints","file_mountpoints","freeze","live_edit","publish_access","custom_stages","stagechg_notification","edit_notification_defaults","edit_allow_notificaton_settings","publish_notification_defaults","publish_allow_notificaton_settings"
+,1,0,0,"Workspace #1",,,,,0,0,0,0,0,0,0,0,0
+"sys_category",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parent","items",,,,
+,28,0,256,0,0,0,0,0,0,0,"Category A",0,0,,,,
+,29,0,512,0,0,0,0,0,0,0,"Category B",0,0,,,,
+,30,0,768,0,0,0,0,0,0,0,"Category C",0,0,,,,
+,31,0,1024,0,0,0,0,0,0,0,"Category A.A",28,0,,,,
+"sys_category_record_mm",,,,,,,,,,,,,,,,,
+,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,,,,
+,28,297,"tt_content",0,1,"categories",,,,,,,,,,,
+,29,297,"tt_content",0,2,"categories",,,,,,,,,,,
+,29,298,"tt_content",0,1,"categories",,,,,,,,,,,
+,30,298,"tt_content",0,2,"categories",,,,,,,,,,,
+,28,299,"tt_content",0,1,"categories",,,,,,,,,,,
+,29,299,"tt_content",0,2,"categories",,,,,,,,,,,
+,31,299,"tt_content",0,3,"categories",,,,,,,,,,,
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories",,,,
+,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",0,2,,,,
+,298,89,512,0,0,0,0,0,0,0,"Regular Element #2",0,2,,,,
+,299,89,256,0,0,0,1,0,0,297,"Regular Element #1",0,3,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+# Should be removed - it is a workspace entry with local & foreign not having ws overlays and there is no other relation to a workspace record
+,"d624da48d7d6427f385a8197cb90c391","sys_category",30,"items",,,,0,1,"tt_content",298,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordResult.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordResult.csv
new file mode 100644
index 0000000000000000000000000000000000000000..f8567a0fd726713ab9c07aac3ad39c37646eef8f
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordResult.csv
@@ -0,0 +1,39 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title",,,,,,,,
+,1,0,256,0,0,0,0,0,"FunctionalTest",,,,,,,,
+,88,1,256,0,0,0,0,0,"DataHandlerTest",,,,,,,,
+,89,88,256,0,0,0,0,0,"Relations",,,,,,,,
+"sys_workspace",,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","title","adminusers","members","db_mountpoints","file_mountpoints","freeze","live_edit","publish_access","custom_stages","stagechg_notification","edit_notification_defaults","edit_allow_notificaton_settings","publish_notification_defaults","publish_allow_notificaton_settings"
+,1,0,0,"Workspace #1",,,,,0,0,0,0,0,0,0,0,0
+"sys_category",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l10n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parent","items",,,,
+,28,0,256,0,0,0,0,0,0,0,"Category A",0,0,,,,
+,29,0,512,0,0,0,0,0,0,0,"Category B",0,0,,,,
+,30,0,768,0,0,0,0,0,0,0,"Category C",0,0,,,,
+,31,0,1024,0,0,0,0,0,0,0,"Category A.A",28,0,,,,
+"sys_category_record_mm",,,,,,,,,,,,,,,,,
+,"uid_local","uid_foreign","tablenames","sorting","sorting_foreign","fieldname",,,,,,,,,,,
+,28,297,"tt_content",0,1,"categories",,,,,,,,,,,
+,29,297,"tt_content",0,2,"categories",,,,,,,,,,,
+,29,298,"tt_content",0,1,"categories",,,,,,,,,,,
+,30,298,"tt_content",0,2,"categories",,,,,,,,,,,
+,28,299,"tt_content",0,1,"categories",,,,,,,,,,,
+,29,299,"tt_content",0,2,"categories",,,,,,,,,,,
+,31,299,"tt_content",0,3,"categories",,,,,,,,,,,
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","image","categories",,,,
+,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",0,2,,,,
+,298,89,512,0,0,0,0,0,0,0,"Regular Element #2",0,2,,,,
+,299,89,256,0,0,0,1,0,0,297,"Regular Element #1",0,3,,,,
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,,,,
+,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,,,,
+,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
+,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
+,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"7d23196104341ffb4a15728711c8da57","sys_category",28,"items",,,,1,1,"tt_content",299,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"55997c67816b709e1d0f0323fea3c39a","sys_category",31,"items",,,,0,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceImport.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceImport.csv
new file mode 100644
index 0000000000000000000000000000000000000000..3d5aaf5a11406d2ca8027a39a027cb7b13de2fbf
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceImport.csv
@@ -0,0 +1,31 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","tx_testirreforeignfield_hotels",,,,,,,
+,1,0,256,0,0,0,0,0,"FunctionalTest",0,,,,,,,
+,88,1,256,0,0,0,0,0,"DataHandlerTest",0,,,,,,,
+,89,88,256,0,0,0,0,0,"Relations",1,,,,,,,
+"sys_workspace",,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","title","adminusers","members","db_mountpoints","file_mountpoints","freeze","live_edit","publish_access","custom_stages","stagechg_notification","edit_notification_defaults","edit_allow_notificaton_settings","publish_notification_defaults","publish_allow_notificaton_settings"
+,1,0,0,"Workspace #1",,,,,0,0,0,0,0,0,0,0,0
+,2,0,1,"Workspace #2",,,,,0,0,0,0,0,0,0,0,0
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","tx_testirreforeignfield_hotels",,,,,
+,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",1,,,,,
+,298,89,512,0,0,0,0,0,0,0,"Regular Element #2",1,,,,,
+,299,89,512,0,0,0,1,0,0,298,"Testing #1",1,,,,,
+"tx_testirreforeignfield_hotel",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","offers",,
+,2,89,1,0,0,0,0,0,0,0,"Hotel #0",89,"pages",,0,,
+,3,89,1,0,0,0,0,0,0,0,"Hotel #1",297,"tt_content","1nff.hotels",2,,
+,5,89,1,0,0,0,0,0,0,0,"Hotel #1",298,"tt_content","1nff.hotels",1,,
+,6,89,1,0,0,0,1,0,0,5,"Hotel #1",298,"tt_content","1nff.hotels",1,,
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+,"8309f9a3ae2a259bdcb29913b7101244","pages",89,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",2,,,,,,
+,"b9be8f0166b062001c138957270e72e2","tt_content",297,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",3,,,,,,
+,"4e8bfa4d76d4cec2d9f6ec62d2974371","tt_content",298,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",5,,,,,,
+# valid - ws exists and records are connected
+,"f735c7fc6863a29d827ca201f60c8055","tt_content",299,"tx_testirreforeignfield_hotels",,,,0,1,"tx_testirreforeignfield_hotel",6,,,,,,
+# invalid - ws 2 is deleted = 1 - should be removed
+,"deletetWorkspace827ca201f60c8055","tt_content",299,"tx_testirreforeignfield_hotels",,,,0,2,"tx_testirreforeignfield_hotel",6,,,,,,
+# invalid - ws 3 does not exist - should be removed
+,"notExistingWorkspacea201f60c8055","tt_content",299,"tx_testirreforeignfield_hotels",,,,0,3,"tx_testirreforeignfield_hotel",6,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceResult.csv b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceResult.csv
new file mode 100644
index 0000000000000000000000000000000000000000..b5aef40c72c1f6ec072639d8394f8c5d024dfda7
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceResult.csv
@@ -0,0 +1,26 @@
+"pages",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","tx_testirreforeignfield_hotels",,,,,,,
+,1,0,256,0,0,0,0,0,"FunctionalTest",0,,,,,,,
+,88,1,256,0,0,0,0,0,"DataHandlerTest",0,,,,,,,
+,89,88,256,0,0,0,0,0,"Relations",1,,,,,,,
+"sys_workspace",,,,,,,,,,,,,,,,,
+,"uid","pid","deleted","title","adminusers","members","db_mountpoints","file_mountpoints","freeze","live_edit","publish_access","custom_stages","stagechg_notification","edit_notification_defaults","edit_allow_notificaton_settings","publish_notification_defaults","publish_allow_notificaton_settings"
+,1,0,0,"Workspace #1",,,,,0,0,0,0,0,0,0,0,0
+,2,0,1,"Workspace #2",,,,,0,0,0,0,0,0,0,0,0
+"tt_content",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","header","tx_testirreforeignfield_hotels",,,,,
+,297,89,256,0,0,0,0,0,0,0,"Regular Element #1",1,,,,,
+,298,89,512,0,0,0,0,0,0,0,"Regular Element #2",1,,,,,
+,299,89,512,0,0,0,1,0,0,298,"Testing #1",1,,,,,
+"tx_testirreforeignfield_hotel",,,,,,,,,,,,,,,,,
+,"uid","pid","sorting","deleted","sys_language_uid","l18n_parent","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","title","parentid","parenttable","parentidentifier","offers",,
+,2,89,1,0,0,0,0,0,0,0,"Hotel #0",89,"pages",,0,,
+,3,89,1,0,0,0,0,0,0,0,"Hotel #1",297,"tt_content","1nff.hotels",2,,
+,5,89,1,0,0,0,0,0,0,0,"Hotel #1",298,"tt_content","1nff.hotels",1,,
+,6,89,1,0,0,0,1,0,0,5,"Hotel #1",298,"tt_content","1nff.hotels",1,,
+"sys_refindex",,,,,,,,,,,,,,,,,
+,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
+,"8309f9a3ae2a259bdcb29913b7101244","pages",89,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",2,,,,,,
+,"b9be8f0166b062001c138957270e72e2","tt_content",297,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",3,,,,,,
+,"4e8bfa4d76d4cec2d9f6ec62d2974371","tt_content",298,"tx_testirreforeignfield_hotels",,,,0,0,"tx_testirreforeignfield_hotel",5,,,,,,
+,"f735c7fc6863a29d827ca201f60c8055","tt_content",299,"tx_testirreforeignfield_hotels",,,,0,1,"tx_testirreforeignfield_hotel",6,,,,,,
diff --git a/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexTest.php b/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9e6c474bc5293721425467b58bd05a6684833dd3
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexTest.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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!
+ */
+
+namespace TYPO3\CMS\Core\Tests\Functional\Database;
+
+use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+class ReferenceIndexTest extends FunctionalTestCase
+{
+    protected $testExtensionsToLoad = [
+        'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_irre_foreignfield',
+    ];
+
+    /**
+     * @test
+     */
+    public function updateIndexRemovesRecordsOfNotExistingWorkspaces(): void
+    {
+        $this->importCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceImport.csv');
+        $result = (new ReferenceIndex())->updateIndex(false);
+        self::assertSame('Index table hosted 1 indexes for non-existing or deleted workspaces, now removed.', $result['errors'][0]);
+        $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/UpdateIndexRemoveNonExistingWorkspaceResult.csv');
+    }
+}
diff --git a/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexWorkspaceLoadedTest.php b/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexWorkspaceLoadedTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..38516e56e334dd08aa19e2f31130a742c7a183d8
--- /dev/null
+++ b/typo3/sysext/core/Tests/Functional/Database/ReferenceIndexWorkspaceLoadedTest.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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!
+ */
+
+namespace TYPO3\CMS\Core\Tests\Functional\Database;
+
+use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
+
+class ReferenceIndexWorkspaceLoadedTest extends FunctionalTestCase
+{
+    protected $coreExtensionsToLoad = [
+        'workspaces',
+    ];
+
+    protected $testExtensionsToLoad = [
+        'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_irre_foreignfield',
+    ];
+
+    /**
+     * @test
+     */
+    public function updateIndexRemovesRecordsOfNotExistingWorkspaces(): void
+    {
+        $this->importCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceImport.csv');
+        $result = (new ReferenceIndex())->updateIndex(false);
+        self::assertSame('Index table hosted 2 indexes for non-existing or deleted workspaces, now removed.', $result['errors'][0]);
+        $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexRemoveNonExistingWorkspaceResult.csv');
+    }
+
+    /**
+     * @test
+     */
+    public function updateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecord(): void
+    {
+        $this->importCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordImport.csv');
+        $result = (new ReferenceIndex())->updateIndex(false);
+        $this->assertCSVDataSet('typo3/sysext/core/Tests/Functional/Database/Fixtures/ReferenceIndex/WorkspaceLoadedUpdateIndexAddsRowsForLocalSideMmHavingForeignWorkspaceRecordResult.csv');
+    }
+}
diff --git a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php
index 0018116cd5a8030156704016c6cce804c4b20f3d..037fa6179e1e5c42d985a96391287b0c753b6b81 100644
--- a/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php
+++ b/typo3/sysext/workspaces/Classes/Hook/DataHandlerHook.php
@@ -562,6 +562,12 @@ class DataHandlerHook
         // Versioned records which contents will be moved into $curVersion
         $isNewRecord = ((int)($curVersion['t3ver_state'] ?? 0) === VersionState::NEW_PLACEHOLDER);
         if ($isNewRecord && is_array($curVersion)) {
+            // @todo: This early return is odd. It means version_swap_processFields() and versionPublishManyToManyRelations()
+            //        below are not called for new records to be published. This is "fine" for mm since mm tables have no
+            //        t3ver_wsid and need no publish as such. For inline relation publishing, this is indirectly resolved by the
+            //        processCmdmap_beforeStart() hook, which adds additional commands for child records - a construct we
+            //        may want to avoid altogether due to its complexity. It would be easier to follow if publish here would
+            //        handle that instead.
             $this->publishNewRecord($table, $curVersion, $dataHandler, $comment, (array)$notificationAlternativeRecipients);
             return;
         }
@@ -632,6 +638,10 @@ class DataHandlerHook
         // In case of swapping and the offline record has a state
         // (like 2 or 4 for deleting or move-pointer) we set the
         // current workspace ID so the record is not deselected.
+        // @todo: It is odd these information are updated in $swapVersion *before* version_swap_processFields
+        //        version_swap_processFields() and versionPublishManyToManyRelations() are called. This leads
+        //        to the situation that versionPublishManyToManyRelations() needs another argument to transfer
+        //        the "from workspace" information which would usually be retrieved by accessing $swapVersion['t3ver_wsid']
         $swapVersion['t3ver_wsid'] = 0;
         $swapVersion['t3ver_stage'] = 0;
         $swapVersion['t3ver_state'] = (string)new VersionState(VersionState::DEFAULT_STATE);
@@ -643,7 +653,7 @@ class DataHandlerHook
                 }
             }
         }
-        $dataHandler->versionPublishManyToManyRelations($table, $curVersion, $swapVersion);
+        $dataHandler->versionPublishManyToManyRelations($table, $curVersion, $swapVersion, $workspaceId);
         unset($swapVersion['uid']);
         // Modify online version to become offline:
         unset($curVersion['uid']);
@@ -987,6 +997,13 @@ class DataHandlerHook
         $dataHandler->registerReferenceIndexRowsForDrop($table, $id, $workspaceId);
         $dataHandler->updateRefIndex($table, $id, 0);
         $this->updateReferenceIndexForL10nOverlays($table, $id, $workspaceId, $dataHandler);
+
+        // When dealing with mm relations on local side, existing refindex rows of the new workspace record
+        // need to be re-calculated for the now live record. Scenario ManyToMany Publish createContentAndAddRelation
+        // These calls are similar to what is done in DH->versionPublishManyToManyRelations() and can not be
+        // used from there since publishing new records does not call that method, see @todo in version_swap().
+        $dataHandler->registerReferenceIndexUpdateForReferencesToItem($table, $id, $workspaceId, 0);
+        $dataHandler->registerReferenceIndexUpdateForReferencesToItem($table, $id, $workspaceId);
     }
 
     /**
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/ActionTest.php
index 5cc5be7380770958f4dad03e4178c8ff75d18e7d..d7d0aa63733afe9d58e73780fdefabd8784b1d5e 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/ActionTest.php
@@ -57,9 +57,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -81,9 +78,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureDoesNotHaveRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -102,9 +96,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -125,9 +116,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -230,9 +218,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -253,9 +238,6 @@ class ActionTest extends AbstractActionTestCase
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Testing #1', 'Category B'));
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -273,9 +255,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -312,9 +291,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -351,9 +327,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -392,9 +365,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -420,8 +390,5 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentIdLast'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/addCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/addCategoryRelation.csv
index e4f10e839b7b83894d63469fe2449126cdbc0a89..f77113537169e8c3a0d06f0d464dc211114e83b2 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/addCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/addCategoryRelation.csv
@@ -44,3 +44,11 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"7d23196104341ffb4a15728711c8da57","sys_category",28,"items",,,,1,1,"tt_content",299,,,,,,
+# Yes. This is a workspace entry for cat 29 (not a ws record) to tt_content 298 (not a ws record either).
+# It still makes sense: When looking at cat 29 in ws 1 - both records 298 and 299 (which is a ws record)
+# are connected to cat 29. So the refindex entry 29-298 is triggered together with the creation of ws
+# record 299 to "complete" the flat refindex table entries for cat 29.
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"55997c67816b709e1d0f0323fea3c39a","sys_category",31,"items",,,,0,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
index 19ea64671cb8a8848cb309c08e7cae6eb2279a43..362781698850fb1c4223ba2bf8d3b8e85d5cd99e 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/changeCategoryRelationSorting.csv
@@ -43,3 +43,7 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+# @todo: Broken. 28->299 sorting 1 and 29->299 sorting 2 ... sys_refindex has no sorting_foreign
+,"7d23196104341ffb4a15728711c8da57","sys_category",28,"items",,,,1,1,"tt_content",299,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyContentOfRelation.csv
index 156b2a72409f9d4886467f0469845428bd4f9e2c..99291279c1281ed30f7f3f56241c7fda8dd5767a 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyContentOfRelation.csv
@@ -43,3 +43,8 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"d624da48d7d6427f385a8197cb90c391","sys_category",30,"items",,,,0,1,"tt_content",298,,,,,,
+,"f65da53fb6e3b34333940d2cffe010a3","sys_category",30,"items",,,,1,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyPage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyPage.csv
index 691b610e9fc28d75471fd25bbc9f70be811b1611..96c05b87463bea3505f4e95ca5a74ffbd7162cf1 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyPage.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/copyPage.csv
@@ -47,3 +47,11 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"bc70e11586947a0c445e348692fd80ba","sys_category",29,"items",,,,3,1,"tt_content",300,,,,,,
+,"d624da48d7d6427f385a8197cb90c391","sys_category",30,"items",,,,0,1,"tt_content",298,,,,,,
+,"f65da53fb6e3b34333940d2cffe010a3","sys_category",30,"items",,,,1,1,"tt_content",299,,,,,,
+,"538e7c228af54d2978dff4ff24d2962c","sys_category",28,"items",,,,0,1,"tt_content",297,,,,,,
+,"8567a86039b572b0c9ac1af154cfb9b1","sys_category",28,"items",,,,1,1,"tt_content",300,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/createContentNAddRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/createContentNAddRelation.csv
index 84c2667aad0741c2d5202179b079184dc79905f5..10d52784afeb745f99ef182431384f4950eb781a 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/createContentNAddRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/createContentNAddRelation.csv
@@ -42,3 +42,6 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteCategoryRelation.csv
index beca40a2ff5e4b9d33e1afdb32048a83ecc90808..e802862ead64a54b1b21a4f49b871b7c484a296c 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteCategoryRelation.csv
@@ -35,10 +35,11 @@
 ,299,89,256,0,0,0,1,0,0,297,"Regular Element #1",0,1,,,,
 "sys_refindex",,,,,,,,,,,,,,,,,
 ,"hash","tablename","recuid","field","flexpointer","softref_key","softref_id","sorting","workspace","ref_table","ref_uid","ref_string",,,,,
-,"01a3ce8c4e3b2bb1aa439dc29081f996","sys_workspace_stage",1,"responsible_persons",,,,0,0,"be_users",3,,,,,,
-,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,,,,
-,"25426f92d44dd2ccf416108462b446e3","sys_workspace",1,"custom_stages",,,,0,0,"sys_workspace_stage",1,,,,,,
 ,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,,,,
+,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
-,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,,,,
+,"25426f92d44dd2ccf416108462b446e3","sys_workspace",1,"custom_stages",,,,0,0,"sys_workspace_stage",1,,,,,,
+,"01a3ce8c4e3b2bb1aa439dc29081f996","sys_workspace_stage",1,"responsible_persons",,,,0,0,"be_users",3,,,,,,
+,"7d23196104341ffb4a15728711c8da57","sys_category",28,"items",,,,1,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteContentOfRelation.csv
index 70806e73c3eb5c35f1479e8d3ad083c0621bfe49..2dfd9a8dc0d00407f8b54af8c0fea45fbb97c9fd 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/deleteContentOfRelation.csv
@@ -43,3 +43,6 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"f65da53fb6e3b34333940d2cffe010a3","sys_category",30,"items",,,,1,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/localizeContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/localizeContentOfRelation.csv
index c4d1211220a584621bbe40537e56a62f754e70c3..0a06f261a61dd16d52dea1ebac9453348ef1c2c6 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/localizeContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/localizeContentOfRelation.csv
@@ -44,3 +44,8 @@
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
 ,"e4afda9b67d6ad42e03f5c797250235d","tt_content",299,"l18n_parent",,,,0,1,"tt_content",298,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"d624da48d7d6427f385a8197cb90c391","sys_category",30,"items",,,,0,1,"tt_content",298,,,,,,
+,"f65da53fb6e3b34333940d2cffe010a3","sys_category",30,"items",,,,1,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyBothsOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyBothsOfRelation.csv
index df1e4f57bcaea3438c511c311a6d50d3db498482..fe5e7562bd9f9b8b6cfaa4c0d85be90bd02e8b75 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyBothsOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyBothsOfRelation.csv
@@ -45,3 +45,5 @@
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
 ,"e69807022342144ed786af9748b90623","sys_category",32,"items",,,,0,1,"tt_content",299,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyContentOfRelation.csv
index 0549c71ffff08c3f9f1a6b9e3c1cc35983a2eb1d..4916dacc0e79442c5e6c912cac383672dc61d51d 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/modifyContentOfRelation.csv
@@ -43,3 +43,6 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"7d23196104341ffb4a15728711c8da57","sys_category",28,"items",,,,1,1,"tt_content",299,,,,,,
+,"6824a5635d464123a7a91770440e1d23","sys_category",29,"items",,,,1,1,"tt_content",298,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/moveContentOfRelationToDifferentPage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/moveContentOfRelationToDifferentPage.csv
index fbc2d915050133724e6f39dbaf201c832ce64209..51f2272e506b6f7f0a8ee7c74f120c5056e64b41 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/moveContentOfRelationToDifferentPage.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Modify/DataSet/moveContentOfRelationToDifferentPage.csv
@@ -43,3 +43,6 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a2784c59b73c994181170d02af23959c","sys_category",29,"items",,,,0,1,"tt_content",297,,,,,,
+,"92e328e25f38d92ecf90478f6b47e671","sys_category",29,"items",,,,2,1,"tt_content",299,,,,,,
+,"f65da53fb6e3b34333940d2cffe010a3","sys_category",30,"items",,,,1,1,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/ActionTest.php
index ef661b9add2ecf6003a08945fd703ed3cb7a5b7d..0f4ce03e2073a2a95da439d0da80b2a86a5f380d 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/ActionTest.php
@@ -54,9 +54,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -76,9 +73,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureDoesNotHaveRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -95,9 +89,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -116,9 +107,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -229,9 +217,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -253,9 +238,6 @@ class ActionTest extends AbstractActionTestCase
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Testing #1', 'Category B'));
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -271,9 +253,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -306,9 +285,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -341,9 +317,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -379,9 +352,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -408,8 +378,5 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentIdLast'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/addCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/addCategoryRelation.csv
index e2e31b6cd3c3d61d2cda725077ae69e9a115f083..7ed9e2f235865b55f99a2afd347813c18ff1511c 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/addCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/addCategoryRelation.csv
@@ -41,3 +41,4 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a8a91b196a05f3f11285176aebc2b2f5","sys_category",31,"items",,,,0,0,"tt_content",297,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyContentOfRelation.csv
index dbaf906b1eb3468bcf7106f0208e5a914fa2fd7f..48c4ca2f856cc097fb1885fbc6e386090bb636db 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyContentOfRelation.csv
@@ -43,3 +43,5 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyPage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyPage.csv
index 4f84e0afc1c7aa2816f3007285ac60fec5fb19e2..56fbffe5042d35c2c52ec096959d51c289d2603c 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyPage.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/copyPage.csv
@@ -47,3 +47,7 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"c9b6f46d28e208f172a6d23329c6ca99","sys_category",29,"items",,,,3,0,"tt_content",300,,,,,,
+,"ec0c2b2cf2e32e44f5bff20c4beefb21","sys_category",28,"items",,,,1,0,"tt_content",300,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/createContentNAddRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/createContentNAddRelation.csv
index 725b50de7b637d8f8b20a46b3431e5579ad61190..97a39fe705a1a8c2c6bd088679c9bb441e52b9a0 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/createContentNAddRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/createContentNAddRelation.csv
@@ -42,3 +42,4 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/deleteCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/deleteCategoryRelation.csv
index cba2b096121749f4ba054354b5af627220175347..62d4078c3a8307af4963660447bf2665225ac78d 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/deleteCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/deleteCategoryRelation.csv
@@ -36,6 +36,5 @@
 ,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,,,,
 ,"25426f92d44dd2ccf416108462b446e3","sys_workspace",1,"custom_stages",,,,0,0,"sys_workspace_stage",1,,,,,,
 ,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,,,,
-,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
-,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"c5335005290004a81e512dfe6948bd69","sys_category",29,"items",,,,0,0,"tt_content",298,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/localizeContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/localizeContentOfRelation.csv
index 74a2d6113c3f4ab513cc450b45877f75f93f7ff0..c1db7957b81449e5db80274017ab86ec7c3b032a 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/localizeContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/Publish/DataSet/localizeContentOfRelation.csv
@@ -44,3 +44,5 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/ActionTest.php b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/ActionTest.php
index 99a781dac3d35f2e11092d4615b09fe758317933..94f64cf6043016c441d0acf30ecaecc916d058cd 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/ActionTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/ActionTest.php
@@ -54,9 +54,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -76,9 +73,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureDoesNotHaveRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C', 'Category A.A'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -95,9 +89,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdFirst)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category A', 'Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -116,9 +107,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -216,9 +204,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -237,9 +222,6 @@ class ActionTest extends AbstractActionTestCase
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Testing #1', 'Category B'));
         self::assertThat($responseSections, $this->getRequestSectionHasRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -255,9 +237,6 @@ class ActionTest extends AbstractActionTestCase
         $responseSections = ResponseContent::fromString((string)$response->getBody())->getSections();
         self::assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint()
             ->setTable(self::TABLE_Content)->setField('header')->setValues('Testing #1'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -290,9 +269,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentId'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -325,9 +301,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -362,9 +335,6 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . self::VALUE_ContentIdLast)->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 
     /**
@@ -388,8 +358,5 @@ class ActionTest extends AbstractActionTestCase
         self::assertThat($responseSections, $this->getRequestSectionStructureHasRecordConstraint()
             ->setRecordIdentifier(self::TABLE_Content . ':' . $this->recordIds['newContentIdLast'])->setRecordField('categories')
             ->setTable(self::TABLE_Category)->setField('title')->setValues('Category B', 'Category C'));
-
-        // @todo: reference index not clean after this test. Needs investigation.
-        $this->assertCleanReferenceIndex = false;
     }
 }
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/addCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/addCategoryRelation.csv
index b5c7aee31526790eb347e8b6fee7b627e53e084d..123cd040fd72a726e84464fad3984af93dc6774a 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/addCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/addCategoryRelation.csv
@@ -41,3 +41,4 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"a8a91b196a05f3f11285176aebc2b2f5","sys_category",31,"items",,,,0,0,"tt_content",297,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyContentOfRelation.csv
index dbaf906b1eb3468bcf7106f0208e5a914fa2fd7f..48c4ca2f856cc097fb1885fbc6e386090bb636db 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyContentOfRelation.csv
@@ -43,3 +43,5 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyPage.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyPage.csv
index 4f84e0afc1c7aa2816f3007285ac60fec5fb19e2..1fef88a342cf67f1c5b33583c43424e0b0a1fff5 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyPage.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/copyPage.csv
@@ -47,3 +47,7 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"c9b6f46d28e208f172a6d23329c6ca99","sys_category",29,"items",,,,3,0,"tt_content",300,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,
+,"ec0c2b2cf2e32e44f5bff20c4beefb21","sys_category",28,"items",,,,1,0,"tt_content",300,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/createContentNAddRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/createContentNAddRelation.csv
index 725b50de7b637d8f8b20a46b3431e5579ad61190..97a39fe705a1a8c2c6bd088679c9bb441e52b9a0 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/createContentNAddRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/createContentNAddRelation.csv
@@ -42,3 +42,4 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/deleteCategoryRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/deleteCategoryRelation.csv
index 10f49ae45c5efb5a8396176759cd930c795b3b5b..51b8ff95248b84382ace3fac025e80b101a6cfc0 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/deleteCategoryRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/deleteCategoryRelation.csv
@@ -36,6 +36,5 @@
 ,"1b70a8e25c22645f7a49a79f57f3cf3f","sys_category",31,"parent",,,,0,0,"sys_category",28,,,,,,
 ,"25426f92d44dd2ccf416108462b446e3","sys_workspace",1,"custom_stages",,,,0,0,"sys_workspace_stage",1,,,,,,
 ,"3c637501ab9c158daa933643bff8cc43","sys_category",28,"items",,,,0,0,"tt_content",297,,,,,,
-,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
-,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"c5335005290004a81e512dfe6948bd69","sys_category",29,"items",,,,0,0,"tt_content",298,,,,,,
diff --git a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/localizeContentOfRelation.csv b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/localizeContentOfRelation.csv
index 74a2d6113c3f4ab513cc450b45877f75f93f7ff0..c1db7957b81449e5db80274017ab86ec7c3b032a 100644
--- a/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/localizeContentOfRelation.csv
+++ b/typo3/sysext/workspaces/Tests/Functional/DataHandling/ManyToMany/PublishAll/DataSet/localizeContentOfRelation.csv
@@ -44,3 +44,5 @@
 ,"aabda97b66f9b693f30d1faf442b37d6","sys_category",29,"items",,,,1,0,"tt_content",298,,,,,,
 ,"b102e2f9b1ed99b14d813363199cb281","sys_category",30,"items",,,,0,0,"tt_content",298,,,,,,
 ,"e19100d609a435906e16432a41b55c72","sys_category",29,"items",,,,0,0,"tt_content",297,,,,,,
+,"40880cf3db51a7c80d8714f9b60409eb","sys_category",29,"items",,,,2,0,"tt_content",299,,,,,,
+,"60e6778effa62e4edb070c954d9643ff","sys_category",30,"items",,,,1,0,"tt_content",299,,,,,,