diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
index 36421e9dcb95a50178ee24e1889cd23b416ff2a7..c9633074704b2963cf618c8ebe3d342712d146d6 100644
--- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php
+++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php
@@ -38,8 +38,6 @@ use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
 use TYPO3\CMS\Core\Database\RelationHandler;
-use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory;
-use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserInterface;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\Imaging\Icon;
@@ -2940,58 +2938,6 @@ class BackendUtility
         return [$TScID, $cPid];
     }
 
-    /**
-     * Returns soft-reference parser for the softRef processing type
-     * Usage: $softRefObj = BackendUtility::softRefParserObj('[parser key]');
-     *
-     * @param string $spKey softRef parser key
-     * @return mixed If available, returns Soft link parser object, otherwise false.
-     * @internal should only be used from within TYPO3 Core
-     * @deprecated will be removed in TYPO3 v12.0. Use SoftReferenceParserFactory->getSoftReferenceParser instead.
-     */
-    public static function softRefParserObj($spKey)
-    {
-        trigger_error(
-            'BackendUtility::softRefParserObj will be removed in TYPO3 v12.0, use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory->getSoftReferenceParser instead.',
-            E_USER_DEPRECATED
-        );
-
-        $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'][$spKey] ?? false;
-        $obj = null;
-        if ($className) {
-            $obj = GeneralUtility::makeInstance($className);
-        }
-        if (!$obj) {
-            try {
-                $obj = GeneralUtility::makeInstance(SoftReferenceParserFactory::class)->getSoftReferenceParser($spKey);
-            } catch (\OutOfBoundsException|\InvalidArgumentException $e) {
-                return false;
-            }
-        }
-        // Build a wrapper to call the API with the legacy findRef() call.
-        if ($obj) {
-            if ($obj instanceof SoftReferenceParserInterface && !method_exists($obj, 'findRef')) {
-                // Build a temporary class acting as a wrapper to call findRef() with the new API.
-                return new class($obj) {
-                    private SoftReferenceParserInterface $parser;
-
-                    public function __construct(SoftReferenceParserInterface $obj)
-                    {
-                        $this->parser = $obj;
-                    }
-
-                    public function findRef($table, $field, $uid, $content, $parserKey, $spParams, $structurePath)
-                    {
-                        $this->parser->setParserKey($parserKey, $spParams);
-                        return $this->parser->parse($table, $field, $uid, $content, $structurePath)->toNullableArray();
-                    }
-                };
-            }
-            return $obj;
-        }
-        return false;
-    }
-
     /**
      * Gets an instance of the runtime cache.
      *
@@ -3002,49 +2948,6 @@ class BackendUtility
         return GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
     }
 
-    /**
-     * Returns array of soft parser references
-     *
-     * @param string $parserList softRef parser list
-     * @return array|bool Array where the parser key is the key and the value is the parameter string, FALSE if no parsers were found
-     * @throws \InvalidArgumentException
-     * @internal should only be used from within TYPO3 Core
-     * @deprecated will be removed in TYPO3 v12.0. Use SoftReferenceParserFactory->getParsersBySoftRefParserList instead.
-     */
-    public static function explodeSoftRefParserList($parserList)
-    {
-        trigger_error(
-            'BackendUtility::explodeSoftRefParserList will be removed in TYPO3 v12.0, use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory->getParsersBySoftRefParserList instead.',
-            E_USER_DEPRECATED
-        );
-
-        // Return immediately if list is blank:
-        if ((string)$parserList === '') {
-            return false;
-        }
-
-        $runtimeCache = self::getRuntimeCache();
-        $cacheId = 'backend-softRefList-' . md5($parserList);
-        $parserListCache = $runtimeCache->get($cacheId);
-        if ($parserListCache !== false) {
-            return $parserListCache;
-        }
-
-        // Otherwise parse the list:
-        $keyList = GeneralUtility::trimExplode(',', $parserList, true);
-        $output = [];
-        foreach ($keyList as $val) {
-            $reg = [];
-            if (preg_match('/^([[:alnum:]_-]+)\\[(.*)\\]$/', $val, $reg)) {
-                $output[$reg[1]] = GeneralUtility::trimExplode(';', $reg[2], true);
-            } else {
-                $output[$val] = '';
-            }
-        }
-        $runtimeCache->set($cacheId, $output);
-        return $output;
-    }
-
     /**
      * Returns TRUE if $modName is set and is found as a main- or submodule in $TBE_MODULES array
      *
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/AbstractSoftReferenceParser.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/AbstractSoftReferenceParser.php
index 1cb76df2d95e554718e4fbc707f2bcffbe77e75c..7343ef1b74125809e99e5a264774ccf7a0350c24 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/AbstractSoftReferenceParser.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/AbstractSoftReferenceParser.php
@@ -56,13 +56,4 @@ abstract class AbstractSoftReferenceParser implements SoftReferenceParserInterfa
     {
         $this->tokenID_basePrefix = implode(':', [$table, $uid, $field, $structurePath, $this->getParserKey()]);
     }
-
-    /**
-     * @internal will be removed in favor of ->parse() in TYPO3 v12.0.
-     */
-    public function findRef(string $table, string $field, int $uid, string $content, string $spKey, array $spParams, string $structurePath = '')
-    {
-        $this->setParserKey($spKey, $spParams);
-        return $this->parse($table, $field, $uid, $content, $structurePath)->toNullableArray();
-    }
 }
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/ExtensionPathSoftReferenceParser.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/ExtensionPathSoftReferenceParser.php
index 57866cde2e8fa1275694028b8fb781b1b6eabcd0..aecb23307315a2c57f85ac269e995a5fd8354a6d 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/ExtensionPathSoftReferenceParser.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/ExtensionPathSoftReferenceParser.php
@@ -44,14 +44,6 @@ class ExtensionPathSoftReferenceParser implements SoftReferenceParserInterface
         );
     }
 
-    /**
-     * @internal will be removed in favor of ->parse() in TYPO3 v12.0.
-     */
-    public function findRef(string $table, string $field, int $uid, string $content, string $spKey, array $spParams, string $structurePath = '')
-    {
-        return $this->parse($table, $field, $uid, $content, $structurePath)->toNullableArray();
-    }
-
     /**
      * @param string $parserKey The softref parser key.
      * @param array $parameters Parameters of the softlink parser. Basically this is the content inside optional []-brackets after the softref keys. Parameters are exploded by ";
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/NotifySoftReferenceParser.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/NotifySoftReferenceParser.php
index 1adb130a2e093caff2b607e14172f734acabc441..d1e73545dfb54d9267f93a3a322fe289859ec0ed 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/NotifySoftReferenceParser.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/NotifySoftReferenceParser.php
@@ -52,12 +52,4 @@ class NotifySoftReferenceParser implements SoftReferenceParserInterface
             ]
         );
     }
-
-    /**
-     * @internal will be removed in favor of ->parse() in TYPO3 v12.0.
-     */
-    public function findRef(string $table, string $field, int $uid, string $content, string $spKey, array $spParams, string $structurePath = '')
-    {
-        return $this->parse($table, $field, $uid, $content, $structurePath)->toNullableArray();
-    }
 }
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserFactory.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserFactory.php
index 939f1dc70b043217580572ad4a2fc34614856ecb..ff0fd809efa7117f920d6fea9c9b45a6413d3022 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserFactory.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserFactory.php
@@ -34,19 +34,6 @@ class SoftReferenceParserFactory
     {
         $this->runtimeCache = $runtimeCache;
         $this->logger = $logger;
-
-        // TODO remove in TYPO3 v12.0
-        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser'] ?? [] as $parserKey => $className) {
-            trigger_error(
-                sprintf(
-                    'The soft reference parser %s for the key "%s" is registered in the global array $GLOBALS[TYPO3_CONF_VARS][SC_OPTIONS][GLOBAL][softRefParser]. This way of registration will stop working in TYPO3 v12.0. Register the class in Configuration/Services.yaml instead.',
-                    $className,
-                    $parserKey
-                ),
-                E_USER_DEPRECATED
-            );
-            $this->softReferenceParsers[$parserKey] = GeneralUtility::makeInstance($className);
-        }
     }
 
     /**
@@ -157,61 +144,7 @@ class SoftReferenceParserFactory
             );
         }
 
-        $softReferenceParser = $this->softReferenceParsers[$softReferenceParserKey];
-
-        // @todo in v12 soft reference parsers, not implementing SoftReferenceParserInterface should throw an exception
-        if ($softReferenceParser instanceof SoftReferenceParserInterface) {
-            return $softReferenceParser;
-        }
-
-        // @todo everything below is deprecated and will be removed in v12
-
-        trigger_error(
-            sprintf('The class %s does not implement %s. The compatibility layer will be dropped in TYPO3 v12.0.', get_class($softReferenceParser), SoftReferenceParserInterface::class),
-            E_USER_DEPRECATED
-        );
-
-        if (!method_exists($softReferenceParser, 'findRef')) {
-            throw new \RuntimeException(
-                sprintf('The class %s must implement the findRef method.', get_class($softReferenceParser)),
-                1627899708
-            );
-        }
-
-        // Build a temporary class acting as a wrapper to call findRef() with the new API.
-        /** @var object $softReferenceParser */
-        return new class($softReferenceParser, $softReferenceParserKey) implements SoftReferenceParserInterface {
-            private object $parser;
-            private string $parserKey;
-            private array $parameters = [];
-            public function __construct(object $softReferenceParser, $parserKey)
-            {
-                $this->parser = $softReferenceParser;
-                $this->parserKey = $parserKey;
-            }
-            public function setParserKey(string $parserKey, array $parameters): void
-            {
-                $this->parserKey = $parserKey;
-                $this->parameters = $parameters;
-            }
-            public function getParserKey(): string
-            {
-                return $this->parserKey;
-            }
-            public function parse(
-                string $table,
-                string $field,
-                int $uid,
-                string $content,
-                string $structurePath = ''
-            ): SoftReferenceParserResult {
-                $result = $this->parser->findRef($table, $field, $uid, $content, $this->parserKey, $this->parameters, $structurePath);
-                if (is_array($result)) {
-                    return SoftReferenceParserResult::create($result['content'] ?? '', $result['elements'] ?? []);
-                }
-                return SoftReferenceParserResult::createWithoutMatches();
-            }
-        };
+        return $this->softReferenceParsers[$softReferenceParserKey];
     }
 
     /**
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserResult.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserResult.php
index 078793c3c3d6285197b0e2cbc9d69c812cd89db4..daa49b13ae9319e816c535898315943888a1fa59 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserResult.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/SoftReferenceParserResult.php
@@ -83,22 +83,4 @@ final class SoftReferenceParserResult
     {
         return $this->elements;
     }
-
-    /**
-     * @internal This method is added for backwards-compatibility of TYPO3 v11, and not part of the official TYPO3 Core API.
-     */
-    public function toNullableArray(): ?array
-    {
-        if (!$this->hasMatched()) {
-            return null;
-        }
-
-        $result = [];
-        if ($this->hasContent()) {
-            $result['content'] = $this->content;
-        }
-        $result['elements'] = $this->elements;
-
-        return $result;
-    }
 }
diff --git a/typo3/sysext/core/Classes/DataHandling/SoftReference/TypolinkSoftReferenceParser.php b/typo3/sysext/core/Classes/DataHandling/SoftReference/TypolinkSoftReferenceParser.php
index 5e9b930cfc5fb94f8b885294be225b171190030c..07e7d59c7ce771acd63c5d32030af70e7c16ad48 100644
--- a/typo3/sysext/core/Classes/DataHandling/SoftReference/TypolinkSoftReferenceParser.php
+++ b/typo3/sysext/core/Classes/DataHandling/SoftReference/TypolinkSoftReferenceParser.php
@@ -19,7 +19,6 @@ namespace TYPO3\CMS\Core\DataHandling\SoftReference;
 
 use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
 use TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent;
 use TYPO3\CMS\Core\LinkHandling\Exception\UnknownLinkHandlerException;
 use TYPO3\CMS\Core\LinkHandling\LinkService;
@@ -35,13 +34,6 @@ use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
  */
 class TypolinkSoftReferenceParser extends AbstractSoftReferenceParser
 {
-    use PublicMethodDeprecationTrait;
-
-    private $deprecatedPublicMethods = [
-        'getTypoLinkParts' => 'getTypoLinkParts() is for internal usage only. It is implicitly called by the parse() method. Calling getTypoLinkParts() will throw and error in v12.',
-        'setTypoLinkPartsElement' => 'setTypoLinkPartsElement() is for internal usage only. It is implicitly called by the parse() method. Calling setTypoLinkPartsElement() will throw an error in v12.',
-    ];
-
     protected EventDispatcherInterface $eventDispatcher;
 
     public function __construct(EventDispatcherInterface $eventDispatcher)
diff --git a/typo3/sysext/core/Classes/Database/SoftReferenceIndex.php b/typo3/sysext/core/Classes/Database/SoftReferenceIndex.php
deleted file mode 100644
index 560c608ad81effc54aac4a8629c73dc41689248a..0000000000000000000000000000000000000000
--- a/typo3/sysext/core/Classes/Database/SoftReferenceIndex.php
+++ /dev/null
@@ -1,149 +0,0 @@
-<?php
-
-/*
- * 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\Database;
-
-use Psr\EventDispatcher\EventDispatcherInterface;
-use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory;
-use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserResult;
-use TYPO3\CMS\Core\DataHandling\SoftReference\TypolinkSoftReferenceParser;
-use TYPO3\CMS\Core\SingletonInterface;
-
-/**
- * Class for processing of the default soft reference types for CMS:
- *
- * - 'substitute' : A full field value targeted for manual substitution (for import /export features)
- * - 'notify' : Just report if a value is found, nothing more.
- * - 'typolink' : references to page id or file, possibly with anchor/target, possibly commaseparated list.
- * - 'typolink_tag' : As typolink, but searching for <link> tag to encapsulate it.
- * - 'email' : Email highlight
- * - 'url' : URL highlights (with a scheme)
- * @deprecated will be removed in TYPO3 v12.0 in favor of SoftReferenceParserInterface
- */
-class SoftReferenceIndex extends TypolinkSoftReferenceParser implements SingletonInterface
-{
-    public string $tokenID_basePrefix;
-    protected SoftReferenceParserFactory $softReferenceParserFactory;
-
-    public function __construct(
-        EventDispatcherInterface $eventDispatcher,
-        SoftReferenceParserFactory $softReferenceParserFactory
-    ) {
-        parent::__construct($eventDispatcher);
-        $this->softReferenceParserFactory = $softReferenceParserFactory;
-        trigger_error(
-            'SoftReferenceIndex will be removed in TYPO3 v12.0, use appropriate TYPO3\CMS\Core\DataHandling\SoftReference\* class instead.',
-            E_USER_DEPRECATED
-        );
-    }
-
-    /**
-     * @deprecated since v11, will be removed in v12
-     */
-    public function findRef($table, $field, $uid, $content, $spKey, $spParams, $structurePath = '')
-    {
-        $this->parserKey = (string)$spKey;
-        $this->setTokenIdBasePrefix($table, (string)$uid, $field, $structurePath);
-
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser($spKey);
-        $softReferenceParser->setParserKey($spKey, $spParams);
-        return $softReferenceParser->parse($table, $field, $uid, $content, $structurePath)->toNullableArray();
-    }
-
-    public function parse(string $table, string $field, int $uid, string $content, string $structurePath = ''): SoftReferenceParserResult
-    {
-        // does nothing
-        return SoftReferenceParserResult::createWithoutMatches();
-    }
-
-    public function setParserKey(string $parserKey, array $parameters): void
-    {
-        // does nothing
-    }
-
-    /**
-     * TypoLink value processing.
-     * Will process input value as a TypoLink value.
-     *
-     * @param string $content The input content to analyze
-     * @param array $spParams Parameters set for the softref parser key in TCA/columns. value "linkList" will split the string by comma before processing.
-     * @return array|null Result array on positive matches, see description above. Otherwise null
-     * @see \TYPO3\CMS\Frontend\ContentObject::typolink()
-     * @see getTypoLinkParts()
-     */
-    public function findRef_typolink($content, $spParams)
-    {
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser('typolink');
-        $softReferenceParser->setParserKey('typolink', (array)$spParams);
-        return $softReferenceParser->parse('', '', '', $content)->toNullableArray();
-    }
-
-    /**
-     * TypoLink tag processing.
-     * Will search for <link ...> and <a> tags in the content string and process any found.
-     *
-     * @param string $content The input content to analyze
-     * @return array|null Result array on positive matches, see description above. Otherwise null
-     * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typolink()
-     * @see getTypoLinkParts()
-     */
-    public function findRef_typolink_tag($content)
-    {
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser('typolink_tag');
-        $softReferenceParser->setParserKey('typolink_tag', []);
-        return $softReferenceParser->parse('', '', '', $content)->toNullableArray();
-    }
-
-    /**
-     * Finding email addresses in content and making them substitutable.
-     *
-     * @param string $content The input content to analyze
-     * @param array $spParams Parameters set for the softref parser key in TCA/columns
-     * @return array|null Result array on positive matches, see description above. Otherwise null
-     */
-    public function findRef_email($content, $spParams)
-    {
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser('email');
-        $softReferenceParser->setParserKey('email', (array)$spParams);
-        return $softReferenceParser->parse('', '', '', $content)->toNullableArray();
-    }
-
-    /**
-     * Finding URLs in content
-     *
-     * @param string $content The input content to analyze
-     * @param array $spParams Parameters set for the softref parser key in TCA/columns
-     * @return array|null Result array on positive matches, see description above. Otherwise null
-     */
-    public function findRef_url($content, $spParams)
-    {
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser('url');
-        $softReferenceParser->setParserKey('url', (array)$spParams);
-        return $softReferenceParser->parse('', '', '', $content)->toNullableArray();
-    }
-
-    /**
-     * Finding reference to files from extensions in content, but only to notify about their existence. No substitution
-     *
-     * @param string $content The input content to analyze
-     * @return array|null Result array on positive matches, see description above. Otherwise null
-     */
-    public function findRef_extension_fileref($content)
-    {
-        $softReferenceParser = $this->softReferenceParserFactory->getSoftReferenceParser('ext_fileref');
-        $softReferenceParser->setParserKey('ext_fileref', []);
-        return $softReferenceParser->parse('', '', '', $content)->toNullableArray();
-    }
-}
diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
index 4e0e6d29ac77cc1e5ee9fa2f0e8238469496db9e..93eaa01b1ba37606112ea87c9c1da9fa321a1b6e 100644
--- a/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
+++ b/typo3/sysext/core/Documentation/Changelog/12.0/Breaking-96107-DeprecatedFunctionalityRemoved.rst
@@ -15,6 +15,7 @@ The following PHP classes that have previously been marked as deprecated for v11
 - :php:`\TYPO3\CMS\Core\Cache\Backend\WincacheBackend`
 - :php:`\TYPO3\CMS\Core\Database\QueryGenerator`
 - :php:`\TYPO3\CMS\Core\Database\QueryView`
+- :php:`\TYPO3\CMS\Core\Database\SoftReferenceIndex`
 - :php:`\TYPO3\CMS\Core\Service\AbstractService`
 - :php:`\TYPO3\CMS\Extbase\Domain\Model\BackendUser`
 - :php:`\TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup`
@@ -44,8 +45,10 @@ The following PHP class methods that have previously been marked as deprecated f
 The following PHP static class methods that have previously been marked as deprecated for v11 and were now removed:
 
 - :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::fixVersioningPid()`
-- :php:`\TYPO3\CMS\Core\Utility\GeneralUtility::stdAuthCode()`
+- :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::softRefParserObj()`
+- :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::explodeSoftRefParserList()`
 - :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::viewOnClick`
+- :php:`\TYPO3\CMS\Core\Utility\GeneralUtility::stdAuthCode()`
 
 The following methods changed signature according to previous deprecations in v11 at the end of the argument list:
 
@@ -61,7 +64,8 @@ The following public class properties have been dropped:
 
 The following class methods visibility have been changed to protected:
 
-- :php:`\Full\Class\Name->methodName`
+- :php:`\TYPO3\CMS\Core\DataHandling\SoftReference\TypolinkSoftReferenceParser->getTypoLinkParts`
+- :php:`\TYPO3\CMS\Core\DataHandling\SoftReference\TypolinkSoftReferenceParser->setTypoLinkPartsElement`
 
 The following class methods visibility have been changed to private:
 
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/EmailSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/EmailSoftReferenceParserTest.php
index c0f4db1143f367a4df4c4e611f152450d3321ac2..85bcd0bb81885ded28eafa7851900b6090e3c0a2 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/EmailSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/EmailSoftReferenceParserTest.php
@@ -26,28 +26,26 @@ class EmailSoftReferenceParserTest extends AbstractSoftReferenceParserTest
         return [
             'Simple email address found' => [
                 'foo@bar.baz',
-                [
-                    'content' => 'foo@bar.baz',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'foo@bar.baz',
-                        ],
+                'content' => 'foo@bar.baz',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'foo@bar.baz',
                     ],
                 ],
+                'hasMatched' => true,
             ],
             'Multiple email addresses found' => [
                 'This is my first email: foo@bar.baz and this is my second email: foo-_2@bar.baz',
-                [
-                    'content' => 'This is my first email: foo@bar.baz and this is my second email: foo-_2@bar.baz',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'foo@bar.baz',
-                        ],
-                        5 => [
-                            'matchString' => 'foo-_2@bar.baz',
-                        ],
+                'content' => 'This is my first email: foo@bar.baz and this is my second email: foo-_2@bar.baz',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'foo@bar.baz',
+                    ],
+                    5 => [
+                        'matchString' => 'foo-_2@bar.baz',
                     ],
                 ],
+                'hasMatched' => true,
             ],
             'Invalid emails are ignored' => [
                 'abc-@mail.com
@@ -58,21 +56,22 @@ class EmailSoftReferenceParserTest extends AbstractSoftReferenceParserTest
                  abc.def@mail#archive.com
                  abc.def@mail
                  abc.def@mail..com',
-                null,
+                'content' => '',
+                'elements' => [],
+                'hasMatched' => false,
             ],
             'E-Mails in html match' => [
                 '<a href="mailto:foo@bar.de">foo@bar.baz</a>',
-                [
-                    'content' => '<a href="mailto:foo@bar.de">foo@bar.baz</a>',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'foo@bar.de',
-                        ],
-                        5 => [
-                            'matchString' => 'foo@bar.baz',
-                        ],
+                'content' => '<a href="mailto:foo@bar.de">foo@bar.baz</a>',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'foo@bar.de',
+                    ],
+                    5 => [
+                        'matchString' => 'foo@bar.baz',
                     ],
                 ],
+                'hasMatched' => true,
             ],
         ];
     }
@@ -81,11 +80,13 @@ class EmailSoftReferenceParserTest extends AbstractSoftReferenceParserTest
      * @test
      * @dataProvider emailSoftReferenceParserTestDataProvider
      */
-    public function emailSoftReferenceParserTest(string $content, ?array $expected): void
+    public function emailSoftReferenceParserTest(string $content, string $expectedContent, array $expectedElements, bool $expectedHasMatched): void
     {
         $subject = $this->getParserByKey('email');
-        $result = $subject->parse('be_users', 'email', 1, $content)->toNullableArray();
-        self::assertSame($expected, $result);
+        $result = $subject->parse('be_users', 'email', 1, $content);
+        self::assertSame($expectedContent, $result->getContent());
+        self::assertSame($expectedElements, $result->getMatchedElements());
+        self::assertSame($expectedHasMatched, $result->hasMatched());
     }
 
     /**
@@ -96,10 +97,11 @@ class EmailSoftReferenceParserTest extends AbstractSoftReferenceParserTest
         $content = 'My email is: foo@bar.baz';
         $subject = $this->getParserByKey('email');
         $subject->setParserKey('email', ['subst']);
-        $result = $subject->parse('be_users', 'email', 1, $content)->toNullableArray();
-        self::assertArrayHasKey('subst', $result['elements'][2]);
-        self::assertArrayHasKey('tokenID', $result['elements'][2]['subst']);
-        unset($result['elements'][2]['subst']['tokenID']);
+        $result = $subject->parse('be_users', 'email', 1, $content);
+        $matchedElements = $result->getMatchedElements();
+        self::assertArrayHasKey('subst', $matchedElements[2]);
+        self::assertArrayHasKey('tokenID', $matchedElements[2]['subst']);
+        unset($matchedElements[2]['subst']['tokenID']);
 
         $expected = [
             2 => [
@@ -110,6 +112,6 @@ class EmailSoftReferenceParserTest extends AbstractSoftReferenceParserTest
                 ],
             ],
         ];
-        self::assertSame($expected, $result['elements']);
+        self::assertSame($expected, $matchedElements);
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/ExtensionPathSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/ExtensionPathSoftReferenceParserTest.php
index 053e95faad9fd77476369a1752cbf4044ea77316..a3d58969653dafb04543b36dc523682330c34093 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/ExtensionPathSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/ExtensionPathSoftReferenceParserTest.php
@@ -25,48 +25,48 @@ class ExtensionPathSoftReferenceParserTest extends AbstractSoftReferenceParserTe
     {
         return [
             'Simple EXT: path has a match' => [
-                'EXT:foobar/Configuration/TypoScript/setup.typoscript',
-                [
-                    'content' => 'EXT:foobar/Configuration/TypoScript/setup.typoscript',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'EXT:foobar/Configuration/TypoScript/setup.typoscript',
-                        ],
+                'text' => 'EXT:foobar/Configuration/TypoScript/setup.typoscript',
+                'content' => 'EXT:foobar/Configuration/TypoScript/setup.typoscript',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'EXT:foobar/Configuration/TypoScript/setup.typoscript',
                     ],
                 ],
+                'hasMatched' => true,
             ],
             'Multiple EXT: paths have matches' => [
-                '
+                'text' => '
                     @import \'EXT:foobar/Configuration/TypoScript/setup1.typoscript\'
                     foo = bar
                     @import "EXT:foobar/Configuration/TypoScript/setup2.typoscript"
                     # some comment
                     <INCLUDE_TYPOSCRIPT: source="FILE:EXT:foobar/Configuration/TypoScript/setup3.typoscript">
                 ',
-                [
-                    'content' => '
+                'content' => '
                     @import \'EXT:foobar/Configuration/TypoScript/setup1.typoscript\'
                     foo = bar
                     @import "EXT:foobar/Configuration/TypoScript/setup2.typoscript"
                     # some comment
                     <INCLUDE_TYPOSCRIPT: source="FILE:EXT:foobar/Configuration/TypoScript/setup3.typoscript">
                 ',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'EXT:foobar/Configuration/TypoScript/setup1.typoscript',
-                        ],
-                        5 => [
-                            'matchString' => 'EXT:foobar/Configuration/TypoScript/setup2.typoscript',
-                        ],
-                        8 => [
-                            'matchString' => 'EXT:foobar/Configuration/TypoScript/setup3.typoscript',
-                        ],
+                'elements' => [
+                    2 => [
+                        'matchString' => 'EXT:foobar/Configuration/TypoScript/setup1.typoscript',
+                    ],
+                    5 => [
+                        'matchString' => 'EXT:foobar/Configuration/TypoScript/setup2.typoscript',
+                    ],
+                    8 => [
+                        'matchString' => 'EXT:foobar/Configuration/TypoScript/setup3.typoscript',
                     ],
                 ],
+                'hasMatched' => true,
             ],
             'No matches returns null' => [
-                '/foobar/Configuration/TypoScript/setup.typoscript',
-                null,
+                'text' => '/foobar/Configuration/TypoScript/setup.typoscript',
+                'content' => '',
+                'elements' => [],
+                'hasMatched' => false,
             ],
         ];
     }
@@ -75,10 +75,12 @@ class ExtensionPathSoftReferenceParserTest extends AbstractSoftReferenceParserTe
      * @test
      * @dataProvider extensionPathSoftReferenceParserDataProvider
      */
-    public function extensionPathSoftReferenceParserTest(string $content, ?array $expected): void
+    public function extensionPathSoftReferenceParserTest(string $content, string $expectedContent, array $expectedElements, bool $expectedHasMatched): void
     {
         $subject = $this->getParserByKey('ext_fileref');
-        $result = $subject->parse('sys_template', 'include_static_file', 1, $content)->toNullableArray();
-        self::assertSame($expected, $result);
+        $result = $subject->parse('sys_template', 'include_static_file', 1, $content);
+        self::assertSame($expectedContent, $result->getContent());
+        self::assertSame($expectedElements, $result->getMatchedElements());
+        self::assertSame($expectedHasMatched, $result->hasMatched());
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/NotifySoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/NotifySoftReferenceParserTest.php
index fd82cf075804dd930a0f2692dbecfa2beb4c5276..bbf06da07d43f4889ef8c1d4caf4a88bc212e00e 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/NotifySoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/NotifySoftReferenceParserTest.php
@@ -27,10 +27,12 @@ class NotifySoftReferenceParserTest extends AbstractSoftReferenceParserTest
     public function notifySoftReferenceParserTest(): void
     {
         $subject = $this->getParserByKey('notify');
-        $result = $subject->parse('aTable', 'aField', 1, 'fooBar')->toNullableArray();
-        $expected = [
-            'matchString' => 'fooBar',
+        $result = $subject->parse('aTable', 'aField', 1, 'fooBar');
+        $expectedElements = [
+            [
+                'matchString' => 'fooBar',
+            ],
         ];
-        self::assertSame($expected, $result['elements'][0]);
+        self::assertSame($expectedElements, $result->getMatchedElements());
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/SubstituteSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/SubstituteSoftReferenceParserTest.php
index d46df8bb809f6dbbe0ffb2c6ce6673de398aaaa9..b54168ee95c181d3954223458f599d63ea7b380e 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/SubstituteSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/SubstituteSoftReferenceParserTest.php
@@ -28,15 +28,17 @@ class SubstituteSoftReferenceParserTest extends AbstractSoftReferenceParserTest
     {
         $subject = $this->getParserByKey('substitute');
         $subject->setParserKey('substitute', []);
-        $result = $subject->parse('aTable', 'aField', 1, 'fooBar')->toNullableArray();
-        unset($result['elements'][0]['subst']['tokenID']);
+        $result = $subject->parse('aTable', 'aField', 1, 'fooBar')->getMatchedElements();
+        unset($result[0]['subst']['tokenID']);
         $expected = [
-            'matchString' => 'fooBar',
-            'subst' => [
-                'type' => 'string',
-                'tokenValue' => 'fooBar',
+            [
+                'matchString' => 'fooBar',
+                'subst' => [
+                    'type' => 'string',
+                    'tokenValue' => 'fooBar',
+                ],
             ],
         ];
-        self::assertSame($expected, $result['elements'][0]);
+        self::assertSame($expected, $result);
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php
index be7fecb5de6af46c645506334381a18508df1189..ba189dbed7c5764e933a9cb40e460012184f9166 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkSoftReferenceParserTest.php
@@ -153,16 +153,17 @@ class TypoLinkSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content']
-        )->toNullableArray();
+        );
+        $matchedElements = $result->getMatchedElements();
 
-        self::assertArrayHasKey('elements', $result);
-        self::assertArrayHasKey($softrefConfiguration['elementKey'], $result['elements']);
+        self::assertTrue($result->hasMatched());
+        self::assertArrayHasKey($softrefConfiguration['elementKey'], $matchedElements);
 
         // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-        unset($result['elements'][$softrefConfiguration['elementKey']]['subst']['tokenID']);
+        unset($matchedElements[$softrefConfiguration['elementKey']]['subst']['tokenID']);
 
         $expectedElement['matchString'] = $softrefConfiguration['matchString'];
-        self::assertEquals($expectedElement, $result['elements'][$softrefConfiguration['elementKey']]);
+        self::assertEquals($expectedElement, $matchedElements[$softrefConfiguration['elementKey']]);
     }
 
     public function findRefReturnsParsedElementsWithFileDataProvider(): array
@@ -256,16 +257,16 @@ class TypoLinkSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content'],
-        )->toNullableArray();
+        );
 
-        self::assertArrayHasKey('elements', $result);
-        self::assertArrayHasKey($softrefConfiguration['elementKey'], $result['elements']);
+        $matchedElements = $result->getMatchedElements();
+        self::assertTrue($result->hasMatched());
 
         // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-        unset($result['elements'][$softrefConfiguration['elementKey']]['subst']['tokenID']);
+        unset($matchedElements[$softrefConfiguration['elementKey']]['subst']['tokenID']);
 
         $expectedElement['matchString'] = $softrefConfiguration['matchString'];
-        self::assertEquals($expectedElement, $result['elements'][$softrefConfiguration['elementKey']]);
+        self::assertEquals($expectedElement, $matchedElements[$softrefConfiguration['elementKey']]);
     }
 
     public function findRefReturnsNullWithFolderDataProvider(): array
@@ -297,9 +298,9 @@ class TypoLinkSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content']
-        )->toNullableArray();
+        );
 
-        self::assertNull($result);
+        self::assertFalse($result->hasMatched());
     }
 
     public function getTypoLinkPartsThrowExceptionWithPharReferencesDataProvider(): array
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php
index 0174bcad5a6d0dedce3a19e1a864e2d3569c74c7..d3b1b0c0fffdd79a7127282af7b36466fb819e9d 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/TypoLinkTagSoftReferenceParserTest.php
@@ -139,16 +139,16 @@ class TypoLinkTagSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content']
-        )->toNullableArray();
+        );
 
-        self::assertArrayHasKey('elements', $result);
-        self::assertArrayHasKey($softrefConfiguration['elementKey'], $result['elements']);
+        $matchedElements = $result->getMatchedElements();
+        self::assertTrue($result->hasMatched());
 
         // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-        unset($result['elements'][$softrefConfiguration['elementKey']]['subst']['tokenID']);
+        unset($matchedElements[$softrefConfiguration['elementKey']]['subst']['tokenID']);
 
         $expectedElement['matchString'] = $softrefConfiguration['matchString'];
-        self::assertEquals($expectedElement, $result['elements'][$softrefConfiguration['elementKey']]);
+        self::assertEquals($expectedElement, $matchedElements[$softrefConfiguration['elementKey']]);
     }
 
     public function findRefReturnsParsedElementsWithFileDataProvider(): array
@@ -200,16 +200,16 @@ class TypoLinkTagSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content'],
-        )->toNullableArray();
+        );
 
-        self::assertArrayHasKey('elements', $result);
-        self::assertArrayHasKey($softrefConfiguration['elementKey'], $result['elements']);
+        $matchedElements = $result->getMatchedElements();
+        self::assertTrue($result->hasMatched());
 
         // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-        unset($result['elements'][$softrefConfiguration['elementKey']]['subst']['tokenID']);
+        unset($matchedElements[$softrefConfiguration['elementKey']]['subst']['tokenID']);
 
         $expectedElement['matchString'] = $softrefConfiguration['matchString'];
-        self::assertEquals($expectedElement, $result['elements'][$softrefConfiguration['elementKey']]);
+        self::assertEquals($expectedElement, $matchedElements[$softrefConfiguration['elementKey']]);
     }
 
     public function findRefReturnsNullWithFolderDataProvider(): array
@@ -246,8 +246,8 @@ class TypoLinkTagSoftReferenceParserTest extends AbstractSoftReferenceParserTest
             'bodytext',
             1,
             $softrefConfiguration['content']
-        )->toNullableArray();
+        );
 
-        self::assertNull($result);
+        self::assertFalse($result->hasMatched());
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/UrlSoftReferenceParserTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/UrlSoftReferenceParserTest.php
index f44cc347166d000f09539e516653ee9b7c8320a5..26a6170271c3d12d0edc1f81b4616fbbbab95c7e 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/UrlSoftReferenceParserTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/SoftReference/UrlSoftReferenceParserTest.php
@@ -26,89 +26,77 @@ class UrlSoftReferenceParserTest extends AbstractSoftReferenceParserTest
         return [
             'Simple url matches' => [
                 'https://foo-bar.baz',
-                [
-                    'content' => 'https://foo-bar.baz',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'https://foo-bar.baz',
-                        ],
+                'content' => 'https://foo-bar.baz',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'https://foo-bar.baz',
                     ],
                 ],
             ],
             'Valid characters by RFC 3986 match' => [
                 'http://ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&\'()*+,;=.foo',
-                [
-                    'content' => 'http://ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&\'()*+,;=.foo',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'http://ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&\'()*+,;=.foo',
-                        ],
+                'content' => 'http://ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&\'()*+,;=.foo',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'http://ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&\'()*+,;=.foo',
                     ],
                 ],
             ],
             'URLs in content match' => [
                 'Lorem ipsum https://foo-bar.baz dolor sit',
-                [
-                    'content' => 'Lorem ipsum https://foo-bar.baz dolor sit',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'https://foo-bar.baz',
-                        ],
+                'content' => 'Lorem ipsum https://foo-bar.baz dolor sit',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'https://foo-bar.baz',
                     ],
                 ],
             ],
             'FTP URLs match' => [
                 'ftp://foo-bar.baz',
-                [
-                    'content' => 'ftp://foo-bar.baz',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'ftp://foo-bar.baz',
-                        ],
+                'content' => 'ftp://foo-bar.baz',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'ftp://foo-bar.baz',
                     ],
                 ],
             ],
             'Full URLs match' => [
                 'https://foo-bar.baz?foo=bar&baz=fizz#anchor',
-                [
-                    'content' => 'https://foo-bar.baz?foo=bar&baz=fizz#anchor',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'https://foo-bar.baz?foo=bar&baz=fizz#anchor',
-                        ],
+                'content' => 'https://foo-bar.baz?foo=bar&baz=fizz#anchor',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'https://foo-bar.baz?foo=bar&baz=fizz#anchor',
                     ],
                 ],
             ],
             'URL encoded URLs match' => [
                 'https://foo-bar.baz?foo%3Dbar%26baz%3Dfi%20zz%23anchor',
-                [
-                    'content' => 'https://foo-bar.baz?foo%3Dbar%26baz%3Dfi%20zz%23anchor',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'https://foo-bar.baz?foo%3Dbar%26baz%3Dfi%20zz%23anchor',
-                        ],
+                'content' => 'https://foo-bar.baz?foo%3Dbar%26baz%3Dfi%20zz%23anchor',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'https://foo-bar.baz?foo%3Dbar%26baz%3Dfi%20zz%23anchor',
                     ],
                 ],
             ],
             'No space character after the last URL matches' => [
                 '<p>Lorem Ipsum<br> https://foo.bar.baz/abc/def/ghi/.</p>',
-                [
-                    'content' => '<p>Lorem Ipsum<br> https://foo.bar.baz/abc/def/ghi/.</p>',
-                    'elements' => [
-                        2 => [
-                            'matchString' => 'https://foo.bar.baz/abc/def/ghi/.',
-                        ],
+                'content' => '<p>Lorem Ipsum<br> https://foo.bar.baz/abc/def/ghi/.</p>',
+                'elements' => [
+                    2 => [
+                        'matchString' => 'https://foo.bar.baz/abc/def/ghi/.',
                     ],
                 ],
             ],
             // The two cases below are handled by typolink_tag
             'URLs in anchor tag attributes do NOT match' => [
                 '<a href="https://foo-bar.baz">some link</a>',
-                null,
+                'content' => '',
+                'elements' => [],
             ],
             'URLs in link tag attributes do NOT match' => [
                 '<link href="https://foo-bar.baz/style.css" rel="stylesheet">',
-                null,
+                'content' => '',
+                'elements' => [],
             ],
         ];
     }
@@ -117,11 +105,12 @@ class UrlSoftReferenceParserTest extends AbstractSoftReferenceParserTest
      * @test
      * @dataProvider urlSoftReferenceParserTestDataProvider
      */
-    public function urlSoftReferenceParserTest(string $content, ?array $expected): void
+    public function urlSoftReferenceParserTest(string $content, string $expectedContent, array $expectedElements): void
     {
         $subject = $this->getParserByKey('url');
-        $result = $subject->parse('pages', 'url', 1, $content)->toNullableArray();
-        self::assertSame($expected, $result);
+        $result = $subject->parse('pages', 'url', 1, $content);
+        self::assertSame($expectedContent, $result->getContent());
+        self::assertSame($expectedElements, $result->getMatchedElements());
     }
 
     /**
@@ -132,10 +121,11 @@ class UrlSoftReferenceParserTest extends AbstractSoftReferenceParserTest
         $content = 'My website is: https://www.foo-bar.baz';
         $subject = $this->getParserByKey('url');
         $subject->setParserKey('url', ['subst']);
-        $result = $subject->parse('pages', 'url', 1, $content)->toNullableArray();
-        self::assertArrayHasKey('subst', $result['elements'][2]);
-        self::assertArrayHasKey('tokenID', $result['elements'][2]['subst']);
-        unset($result['elements'][2]['subst']['tokenID']);
+        $result = $subject->parse('pages', 'url', 1, $content);
+        $matchedElements = $result->getMatchedElements();
+        self::assertArrayHasKey('subst', $matchedElements[2]);
+        self::assertArrayHasKey('tokenID', $matchedElements[2]['subst']);
+        unset($matchedElements[2]['subst']['tokenID']);
 
         $expected = [
             2 => [
@@ -146,6 +136,6 @@ class UrlSoftReferenceParserTest extends AbstractSoftReferenceParserTest
                 ],
             ],
         ];
-        self::assertSame($expected, $result['elements']);
+        self::assertSame($expected, $matchedElements);
     }
 }
diff --git a/typo3/sysext/core/Tests/UnitDeprecated/Database/SoftReferenceIndexTest.php b/typo3/sysext/core/Tests/UnitDeprecated/Database/SoftReferenceIndexTest.php
deleted file mode 100644
index d7a041769958a3927255529fd0b414661291c01c..0000000000000000000000000000000000000000
--- a/typo3/sysext/core/Tests/UnitDeprecated/Database/SoftReferenceIndexTest.php
+++ /dev/null
@@ -1,516 +0,0 @@
-<?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\Unit\Database;
-
-use Prophecy\Argument;
-use Prophecy\PhpUnit\ProphecyTrait;
-use Psr\EventDispatcher\EventDispatcherInterface;
-use Psr\Log\LoggerInterface;
-use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
-use TYPO3\CMS\Core\Database\SoftReferenceIndex;
-use TYPO3\CMS\Core\DataHandling\SoftReference\NotifySoftReferenceParser;
-use TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserFactory;
-use TYPO3\CMS\Core\DataHandling\SoftReference\TypolinkSoftReferenceParser;
-use TYPO3\CMS\Core\DataHandling\SoftReference\TypolinkTagSoftReferenceParser;
-use TYPO3\CMS\Core\Resource\File;
-use TYPO3\CMS\Core\Resource\Folder;
-use TYPO3\CMS\Core\Resource\ResourceFactory;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
-
-/**
- * Test case
- */
-class SoftReferenceIndexTest extends UnitTestCase
-{
-    use ProphecyTrait;
-
-    protected $resetSingletonInstances = true;
-
-    protected function createSoftReferenceParserFactory(): SoftReferenceParserFactory
-    {
-        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
-        $runtimeCache = $this->prophesize(FrontendInterface::class);
-        $runtimeCache->get(Argument::any())->willReturn(false);
-        $runtimeCache->set(Argument::cetera())->willReturn(null);
-        $logger = $this->prophesize(LoggerInterface::class);
-
-        $softReferenceParserFactory = new SoftReferenceParserFactory($runtimeCache->reveal(), $logger->reveal());
-        $softReferenceParserFactory->addParser(new TypolinkSoftReferenceParser($eventDispatcher->reveal()), 'typolink');
-        $softReferenceParserFactory->addParser(new TypolinkTagSoftReferenceParser(), 'typolink_tag');
-
-        return $softReferenceParserFactory;
-    }
-
-    protected function getSoftReferenceParserInstance(): SoftReferenceIndex
-    {
-        $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
-
-        return new SoftReferenceIndex($eventDispatcher->reveal(), $this->createSoftReferenceParserFactory());
-    }
-
-    public function findRefReturnsParsedElementsDataProvider(): array
-    {
-        return [
-            'link to page' => [
-                [
-                    'typolink' => [
-                        'content' => 't3://page?uid=42',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 't3://page?uid=42',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="t3://page?uid=42">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a href="t3://page?uid=42">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'pages:42',
-                        'tokenValue' => 42,
-                    ],
-                ],
-            ],
-            'link to page with properties' => [
-                [
-                    'typolink_tag' => [
-                        'content' => '<p><a class="link-page" href="t3://page?uid=42" target="_top" title="Foo">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a class="link-page" href="t3://page?uid=42" target="_top" title="Foo">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'pages:42',
-                        'tokenValue' => '42',
-                    ],
-                ],
-            ],
-            'link to page with just a number' => [
-                [
-                    'typolink' => [
-                        'content' => '42',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => '42',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'pages:42',
-                        'tokenValue' => '42',
-                    ],
-                ],
-            ],
-            'link to page with just a number and type comma-separated' => [
-                [
-                    'typolink' => [
-                        'content' => '42,100',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => '42,100',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'pages:42',
-                        'tokenValue' => '42',
-                    ],
-                ],
-            ],
-            'link to external URL without scheme' => [
-                [
-                    'typolink' => [
-                        'content' => 'www.example.com',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'www.example.com',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a class="link-page" href="www.example.com" target="_top" title="Foo">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a class="link-page" href="www.example.com" target="_top" title="Foo">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'external',
-                        'tokenValue' => 'http://www.example.com',
-                    ],
-                ],
-            ],
-            'link to external URL with scheme' => [
-                [
-                    'typolink' => [
-                        'content' => 'https://www.example.com',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'https://www.example.com',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a class="link-page" href="https://www.example.com" target="_top" title="Foo">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a class="link-page" href="https://www.example.com" target="_top" title="Foo">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'external',
-                        'tokenValue' => 'https://www.example.com',
-                    ],
-                ],
-            ],
-            'link to email' => [
-                [
-                    'typolink' => [
-                        'content' => 'mailto:test@example.com',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'mailto:test@example.com',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="mailto:test@example.com">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a href="mailto:test@example.com">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'string',
-                        'tokenValue' => 'test@example.com',
-                    ],
-                ],
-            ],
-            'link to email without schema' => [
-                [
-                    'typolink' => [
-                        'content' => 'test@example.com',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'test@example.com',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="test@example.com">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a href="test@example.com">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'string',
-                        'tokenValue' => 'test@example.com',
-                    ],
-                ],
-            ],
-            'link to phone number' => [
-                [
-                    'typolink' => [
-                        'content' => 'tel:0123456789',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'tel:0123456789',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="tel:0123456789">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a href="tel:0123456789">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'string',
-                        'tokenValue' => '0123456789',
-                    ],
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider findRefReturnsParsedElementsDataProvider
-     * @param array $softrefConfiguration
-     * @param array $expectedElement
-     */
-    public function findRefReturnsParsedElements(array $softrefConfiguration, array $expectedElement): void
-    {
-        foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = $this->getSoftReferenceParserInstance();
-            $result = $subject->findRef(
-                'tt_content',
-                'bodytext',
-                1,
-                $configuration['content'],
-                $softrefKey,
-                []
-            );
-
-            self::assertArrayHasKey('elements', $result);
-            self::assertArrayHasKey($configuration['elementKey'], $result['elements']);
-
-            // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-            unset($result['elements'][$configuration['elementKey']]['subst']['tokenID']);
-
-            $expectedElement['matchString'] = $configuration['matchString'];
-            self::assertEquals($expectedElement, $result['elements'][$configuration['elementKey']]);
-        }
-    }
-
-    public function findRefReturnsParsedElementsWithFileDataProvider(): array
-    {
-        return [
-            'link to file' => [
-                [
-                    'typolink' => [
-                        'content' => 't3://file?uid=42',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 't3://file?uid=42',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="t3://file?uid=42">Click here</a></p>',
-                        'elementKey' => 1,
-                        'matchString' => '<a href="t3://file?uid=42">',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'sys_file:42',
-                        'tokenValue' => 'file:42',
-                    ],
-                ],
-            ],
-            'file with t3 mixed syntax' => [
-                [
-                    'typolink' => [
-                        'content' => 't3://file?identifier=42',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 't3://file?identifier=42',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'sys_file:42',
-                        'tokenValue' => 'file:42',
-                    ],
-                ],
-            ],
-            'link to file with old FAL object syntax' => [
-                [
-                    'typolink' => [
-                        'content' => 'file:42',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'file:42',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'sys_file:42',
-                        'tokenValue' => 'file:42',
-                    ],
-                ],
-            ],
-            'link to file with simple file path' => [
-                [
-                    'typolink' => [
-                        'content' => 'fileadmin/download.jpg',
-                        'elementKey' => '8695f308356bcca1acac2749152a44a9:0',
-                        'matchString' => 'fileadmin/download.jpg',
-                    ],
-                ],
-                [
-                    'subst' => [
-                        'type' => 'db',
-                        'recordRef' => 'sys_file:42',
-                        'tokenValue' => 'file:42',
-                    ],
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider findRefReturnsParsedElementsWithFileDataProvider
-     * @param array $softrefConfiguration
-     * @param array $expectedElement
-     */
-    public function findRefReturnsParsedElementsWithFile(array $softrefConfiguration, array $expectedElement): void
-    {
-        $fileObject = $this->prophesize(File::class);
-        $fileObject->getUid()->willReturn(42)->shouldBeCalledTimes(count($softrefConfiguration));
-
-        $resourceFactory = $this->prophesize(ResourceFactory::class);
-        $resourceFactory->getFileObject('42')->willReturn($fileObject->reveal());
-        // For `t3://file?identifier=42` handling
-        $resourceFactory->getFileObjectFromCombinedIdentifier('42')->willReturn($fileObject->reveal());
-        // For `file:23` handling
-        $resourceFactory->retrieveFileOrFolderObject('42')->willReturn($fileObject->reveal());
-        // For `fileadmin/download.jpg` handling
-        $resourceFactory->retrieveFileOrFolderObject('fileadmin/download.jpg')->willReturn($fileObject->reveal());
-
-        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
-
-        foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = $this->getSoftReferenceParserInstance();
-            $result = $subject->findRef(
-                'tt_content',
-                'bodytext',
-                1,
-                $configuration['content'],
-                $softrefKey,
-                []
-            );
-
-            self::assertArrayHasKey('elements', $result);
-            self::assertArrayHasKey($configuration['elementKey'], $result['elements']);
-
-            // Remove tokenID as this one depends on the softrefKey and doesn't need to be verified
-            unset($result['elements'][$configuration['elementKey']]['subst']['tokenID']);
-
-            $expectedElement['matchString'] = $configuration['matchString'];
-            self::assertEquals($expectedElement, $result['elements'][$configuration['elementKey']]);
-        }
-    }
-
-    public function findRefReturnsNullWithFolderDataProvider(): array
-    {
-        return [
-            'link to folder' => [
-                [
-                    'typolink' => [
-                        'content' => 't3://folder?storage=1&amp;identifier=%2Ffoo%2Fbar%2Fbaz',
-                    ],
-                    'typolink_tag' => [
-                        'content' => '<p><a href="t3://folder?storage=1&amp;identifier=%2Ffoo%2Fbar%2Fbaz">Click here</a></p>',
-                    ],
-                ],
-            ],
-            'link to folder with properties' => [
-                [
-                    'typolink_tag' => [
-                        'content' => '<p><a class="link-page" href="t3://folder?storage=1&amp;identifier=%2Ffoo%2Fbar%2Fbaz" target="_top" title="Foo">Click here</a></p>',
-                    ],
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider findRefReturnsNullWithFolderDataProvider
-     * @param array $softrefConfiguration
-     */
-    public function findRefReturnsNullWithFolder(array $softrefConfiguration): void
-    {
-        $folderObject = $this->prophesize(Folder::class);
-
-        $resourceFactory = $this->prophesize(ResourceFactory::class);
-        $resourceFactory->getFolderObjectFromCombinedIdentifier('1:/foo/bar/baz')->willReturn($folderObject->reveal())->shouldBeCalledTimes(count($softrefConfiguration));
-        GeneralUtility::setSingletonInstance(ResourceFactory::class, $resourceFactory->reveal());
-
-        foreach ($softrefConfiguration as $softrefKey => $configuration) {
-            $subject = $this->getSoftReferenceParserInstance();
-            $result = $subject->findRef(
-                'tt_content',
-                'bodytext',
-                1,
-                $configuration['content'],
-                $softrefKey,
-                []
-            );
-
-            self::assertNull($result);
-        }
-    }
-
-    public function getTypoLinkPartsThrowExceptionWithPharReferencesDataProvider(): array
-    {
-        return [
-            'URL encoded local' => [
-                'phar%3a//some-file.jpg',
-            ],
-            'URL encoded absolute' => [
-                'phar%3a///path/some-file.jpg',
-            ],
-            'not URL encoded local' => [
-                'phar://some-file.jpg',
-            ],
-            'not URL encoded absolute' => [
-                'phar:///path/some-file.jpg',
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider getTypoLinkPartsThrowExceptionWithPharReferencesDataProvider
-     */
-    public function getTypoLinkPartsThrowExceptionWithPharReferences(string $pharUrl): void
-    {
-        $this->expectException(\RuntimeException::class);
-        $this->expectExceptionCode(1530030672);
-        ($this->getSoftReferenceParserInstance())->getTypoLinkParts($pharUrl, 'aTable', 0);
-    }
-
-    /**
-     * Registration by new DI should not override registration by global array.
-     *
-     * @test
-     */
-    public function mixedRegistrationBehaviour(): void
-    {
-        $softReferenceParserFactory = $this->createSoftReferenceParserFactory();
-        $softReferenceParserFactory->addParser(new NotifySoftReferenceParser(), 'typolink');
-        $softReferenceParser = $softReferenceParserFactory->getSoftReferenceParser('typolink');
-
-        self::assertTrue(get_class($softReferenceParser) === TypolinkSoftReferenceParser::class);
-    }
-
-    /**
-     * @test
-     */
-    public function softReferenceParserFactoryAddsParserInGlobalsArray(): void
-    {
-        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'] = [
-            'GLOBAL' => [
-                'softRefParser' => [
-                    'substitute' => \TYPO3\CMS\Core\DataHandling\SoftReference\SubstituteSoftReferenceParser::class,
-                ],
-            ],
-        ];
-        $runtimeCache = $this->prophesize(FrontendInterface::class);
-        $logger = $this->prophesize(LoggerInterface::class);
-
-        $softReferenceParserFactory = new SoftReferenceParserFactory($runtimeCache->reveal(), $logger->reveal());
-
-        self::assertIsObject($softReferenceParserFactory->getSoftReferenceParser('substitute'));
-    }
-
-    /**
-     * This simply shouldn't throw an exception.
-     * @test
-     */
-    public function declaringNonExistingParserKeysWillNotThrowAnException()
-    {
-        $softReferenceParserFactory = $this->createSoftReferenceParserFactory();
-        foreach ($softReferenceParserFactory->getParsersBySoftRefParserList('idonotexist,typolink_tag') as $softReferenceParser) {
-            // Do nothing
-        }
-    }
-}
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
index d585244fc7894221582761c32f23f9261c39f777..cd2948bcd8939f530e8f68699996c23a3952c841 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
@@ -1785,6 +1785,7 @@ return [
     'TYPO3\CMS\Core\Database\SoftReferenceIndex' => [
         'restFiles' => [
             'Deprecation-94687-SoftReferenceIndex.rst',
+            'Breaking-96107-DeprecatedFunctionalityRemoved.rst',
         ],
     ],
     'TYPO3\CMS\Frontend\ContentObject\EditPanelContentObject' => [
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
index 5db349fe8c7cd53c81fc154b6a1e978f1d0e7ded..738bd623e8c85e1cc561d1364197981617c4ca02 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallStaticMatcher.php
@@ -1157,6 +1157,7 @@ return [
         'maximumNumberOfArguments' => 1,
         'restFiles' => [
             'Deprecation-94687-SoftReferenceIndex.rst',
+            'Breaking-96107-DeprecatedFunctionalityRemoved.rst',
         ],
     ],
     'TYPO3\CMS\Backend\Utility\BackendUtility::explodeSoftRefParserList' => [
@@ -1164,6 +1165,7 @@ return [
         'maximumNumberOfArguments' => 1,
         'restFiles' => [
             'Deprecation-94687-SoftReferenceIndex.rst',
+            'Breaking-96107-DeprecatedFunctionalityRemoved.rst',
         ],
     ],
     'TYPO3\CMS\Core\Utility\GeneralUtility::minifyJavaScript' => [