diff --git a/composer.json b/composer.json
index e3bef379af0335483c87e0e4d62e988ca199d412..1bf994954bf70fc5620dec1fb2b6ce69c4c50354 100644
--- a/composer.json
+++ b/composer.json
@@ -123,6 +123,7 @@
 		"webmozart/assert": "^1.11.0"
 	},
 	"suggest": {
+		"ext-apcu": "Needed when non-default APCU based cache backends are used",
 		"ext-gd": "GDlib/Freetype is required for building images with text (GIFBUILDER) and can also be used to scale images",
 		"ext-fileinfo": "Used for proper file type detection in the file abstraction layer",
 		"ext-zlib": "TYPO3 uses zlib for amongst others output compression and un/packing t3x extension files",
diff --git a/typo3/sysext/core/Classes/Cache/Backend/ApcuBackend.php b/typo3/sysext/core/Classes/Cache/Backend/ApcuBackend.php
index a9a8b36ad37bb68925da166234d45c60b0cc7423..04a91243c8d59b7fc09cd225ff048796ea62a05a 100644
--- a/typo3/sysext/core/Classes/Cache/Backend/ApcuBackend.php
+++ b/typo3/sysext/core/Classes/Cache/Backend/ApcuBackend.php
@@ -16,58 +16,37 @@
 namespace TYPO3\CMS\Core\Cache\Backend;
 
 use TYPO3\CMS\Core\Cache\Exception;
-use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Core\Environment;
 
 /**
  * A caching backend which stores cache entries by using APCu.
  *
+ * The APCu backend is not very good with tagging and scales O(2n) with the
+ * number of tags. Do not use this backend if the data to be cached has many tags!
+ *
  * This backend uses the following types of keys:
  * - tag_xxx
- * xxx is tag name, value is array of associated identifiers identifier. This
- * is "forward" tag index. It is mainly used for obtaining content by tag
- * (get identifier by tag -> get content by identifier)
+ *   xxx is tag name, value is array of associated identifiers identifier. This
+ *   is "forward" tag index. It is mainly used for obtaining content by tag
+ *   (get identifier by tag -> get content by identifier)
  * - ident_xxx
- * xxx is identifier, value is array of associated tags. This is "reverse" tag
- * index. It provides quick access for all tags associated with this identifier
- * and used when removing the identifier
+ *   xxx is identifier, value is array of associated tags. This is "reverse" tag
+ *   index. It provides quick access for all tags associated with this identifier
+ *   and used when removing the identifier
  *
- * Each key is prepended with a prefix. By default prefix consists from two parts
+ * Each key is prepended with a prefix. The prefix makes sure keys from the different
+ * installations do not conflict. By default, prefix consists from two parts
  * separated by underscore character and ends in yet another underscore character:
  * - "TYPO3"
- * - MD5 of path to TYPO3 and user running TYPO3
- * This prefix makes sure that keys from the different installations do not
- * conflict.
+ * - Hash of path to TYPO3 and user running TYPO3
  */
-class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
+final class ApcuBackend extends AbstractBackend implements TaggableBackendInterface, TransientBackendInterface
 {
     /**
-     * A prefix to separate stored data from other data possible stored in the APC
-     *
-     * @var string
+     * A prefix to separate stored data from other data possible stored in the APC.
      */
-    protected $identifierPrefix;
-
-    /**
-     * Set the cache identifier prefix.
-     *
-     * @param string $identifierPrefix
-     */
-    protected function setIdentifierPrefix($identifierPrefix)
-    {
-        $this->identifierPrefix = $identifierPrefix;
-    }
-
-    /**
-     * Retrieves the cache identifier prefix.
-     *
-     * @return string
-     */
-    protected function getIdentifierPrefix()
-    {
-        return $this->identifierPrefix;
-    }
+    private string $identifierPrefix = '';
 
     /**
      * Constructs this backend
@@ -90,34 +69,29 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
     /**
      * Initializes the identifier prefix when setting the cache.
      */
-    public function setCache(FrontendInterface $cache)
+    public function setCache(FrontendInterface $cache): void
     {
         parent::setCache($cache);
-        $pathHash = md5(Environment::getProjectPath() . $this->context . $cache->getIdentifier());
-        $this->setIdentifierPrefix('TYPO3_' . $pathHash);
+        $this->identifierPrefix = 'TYPO3_' . hash('xxh3', Environment::getProjectPath() . $this->context . $cache->getIdentifier()) . '_';
     }
 
     /**
      * Saves data in the cache.
      *
      * @param string $entryIdentifier An identifier for this specific cache entry
-     * @param string $data The data to be stored
+     * @param mixed $data The data to be stored
      * @param array $tags Tags to associate with this cache entry
      * @param int $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited lifetime.
      * @throws Exception if no cache frontend has been set.
-     * @throws InvalidDataException if $data is not a string
      */
-    public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
+    public function set($entryIdentifier, $data, array $tags = [], $lifetime = null): void
     {
         if (!$this->cache instanceof FrontendInterface) {
             throw new Exception('No cache frontend has been set yet via setCache().', 1232986118);
         }
-        if (!is_string($data)) {
-            throw new InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1232986125);
-        }
         $tags[] = '%APCBE%' . $this->cacheIdentifier;
         $expiration = $lifetime ?? $this->defaultLifetime;
-        $success = apcu_store($this->getIdentifierPrefix() . $entryIdentifier, $data, $expiration);
+        $success = apcu_store($this->identifierPrefix . $entryIdentifier, $data, $expiration);
         if ($success === true) {
             $this->removeIdentifierFromAllTags($entryIdentifier);
             $this->addIdentifierToTags($entryIdentifier, $tags);
@@ -132,10 +106,10 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
      * @param string $entryIdentifier An identifier which describes the cache entry to load
      * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
      */
-    public function get($entryIdentifier)
+    public function get($entryIdentifier): mixed
     {
         $success = false;
-        $value = apcu_fetch($this->getIdentifierPrefix() . $entryIdentifier, $success);
+        $value = apcu_fetch($this->identifierPrefix . $entryIdentifier, $success);
         return $success ? $value : $success;
     }
 
@@ -145,10 +119,10 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
      * @param string $entryIdentifier An identifier specifying the cache entry
      * @return bool TRUE if such an entry exists, FALSE if not
      */
-    public function has($entryIdentifier)
+    public function has($entryIdentifier): bool
     {
         $success = false;
-        apcu_fetch($this->getIdentifierPrefix() . $entryIdentifier, $success);
+        apcu_fetch($this->identifierPrefix . $entryIdentifier, $success);
         return $success;
     }
 
@@ -160,10 +134,10 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
      * @param string $entryIdentifier Specifies the cache entry to remove
      * @return bool TRUE if (at least) an entry could be removed or FALSE if no entry was found
      */
-    public function remove($entryIdentifier)
+    public function remove($entryIdentifier): bool
     {
         $this->removeIdentifierFromAllTags($entryIdentifier);
-        return apcu_delete($this->getIdentifierPrefix() . $entryIdentifier);
+        return apcu_delete($this->identifierPrefix . $entryIdentifier);
     }
 
     /**
@@ -173,36 +147,22 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
      * @param string $tag The tag to search for
      * @return array An array with identifiers of all matching entries. An empty array if no entries matched
      */
-    public function findIdentifiersByTag($tag)
+    public function findIdentifiersByTag($tag): array
     {
         $success = false;
-        $identifiers = apcu_fetch($this->getIdentifierPrefix() . 'tag_' . $tag, $success);
+        $identifiers = apcu_fetch($this->identifierPrefix . 'tag_' . $tag, $success);
         if ($success === false) {
             return [];
         }
         return (array)$identifiers;
     }
 
-    /**
-     * Finds all tags for the given identifier. This function uses reverse tag
-     * index to search for tags.
-     *
-     * @param string $identifier Identifier to find tags by
-     * @return array Array with tags
-     */
-    protected function findTagsByIdentifier($identifier)
-    {
-        $success = false;
-        $tags = apcu_fetch($this->getIdentifierPrefix() . 'ident_' . $identifier, $success);
-        return $success ? (array)$tags : [];
-    }
-
     /**
      * Removes all cache entries of this cache.
      *
      * @throws Exception
      */
-    public function flush()
+    public function flush(): void
     {
         if (!$this->cache instanceof FrontendInterface) {
             throw new Exception('Yet no cache frontend has been set via setCache().', 1232986571);
@@ -215,7 +175,7 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
      *
      * @param string $tag The tag the entries must have
      */
-    public function flushByTag($tag)
+    public function flushByTag($tag): void
     {
         $identifiers = $this->findIdentifiersByTag($tag);
         foreach ($identifiers as $identifier) {
@@ -225,10 +185,8 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
 
     /**
      * Associates the identifier with the given tags
-     *
-     * @param string $entryIdentifier
      */
-    protected function addIdentifierToTags($entryIdentifier, array $tags)
+    private function addIdentifierToTags(string $entryIdentifier, array $tags): void
     {
         // Get identifier-to-tag index to look for updates
         $existingTags = $this->findTagsByIdentifier($entryIdentifier);
@@ -239,7 +197,7 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
             $identifiers = $this->findIdentifiersByTag($tag);
             if (!in_array($entryIdentifier, $identifiers, true)) {
                 $identifiers[] = $entryIdentifier;
-                apcu_store($this->getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
+                apcu_store($this->identifierPrefix . 'tag_' . $tag, $identifiers);
             }
             // Test if identifier-to-tag index needs update
             if (!in_array($tag, $existingTags, true)) {
@@ -250,16 +208,14 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
 
         // Update identifier-to-tag index if needed
         if ($existingTagsUpdated) {
-            apcu_store($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier, $existingTags);
+            apcu_store($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
         }
     }
 
     /**
      * Removes association of the identifier with the given tags
-     *
-     * @param string $entryIdentifier
      */
-    protected function removeIdentifierFromAllTags($entryIdentifier)
+    private function removeIdentifierFromAllTags(string $entryIdentifier): void
     {
         // Get tags for this identifier
         $tags = $this->findTagsByIdentifier($entryIdentifier);
@@ -274,20 +230,29 @@ class ApcuBackend extends AbstractBackend implements TaggableBackendInterface
             if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
                 unset($identifiers[$key]);
                 if (!empty($identifiers)) {
-                    apcu_store($this->getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
+                    apcu_store($this->identifierPrefix . 'tag_' . $tag, $identifiers);
                 } else {
-                    apcu_delete($this->getIdentifierPrefix() . 'tag_' . $tag);
+                    apcu_delete($this->identifierPrefix . 'tag_' . $tag);
                 }
             }
         }
         // Clear reverse tag index for this identifier
-        apcu_delete($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier);
+        apcu_delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
     }
 
     /**
-     * Does nothing, as APCu does GC itself
+     * Finds all tags for the given identifier. This function uses reverse tag
+     * index to search for tags.
      */
-    public function collectGarbage()
+    private function findTagsByIdentifier(string $identifier): array
+    {
+        $success = false;
+        $tags = apcu_fetch($this->identifierPrefix . 'ident_' . $identifier, $success);
+        return $success ? (array)$tags : [];
+    }
+
+    public function collectGarbage(): void
     {
+        // Noop, APCu has internal GC
     }
 }
diff --git a/typo3/sysext/core/Tests/Unit/Cache/Backend/ApcuBackendTest.php b/typo3/sysext/core/Tests/Functional/Cache/Backend/ApcuBackendTest.php
similarity index 71%
rename from typo3/sysext/core/Tests/Unit/Cache/Backend/ApcuBackendTest.php
rename to typo3/sysext/core/Tests/Functional/Cache/Backend/ApcuBackendTest.php
index 7dfe77af01e69a70bbc18d1501dff128a73f6b60..543d830eb4d51afc1185606578cce38547abd553 100644
--- a/typo3/sysext/core/Tests/Unit/Cache/Backend/ApcuBackendTest.php
+++ b/typo3/sysext/core/Tests/Functional/Cache/Backend/ApcuBackendTest.php
@@ -15,33 +15,38 @@ declare(strict_types=1);
  * The TYPO3 project - inspiring people to share!
  */
 
-namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
+namespace TYPO3\CMS\Core\Tests\Functional\Cache\Backend;
 
 use TYPO3\CMS\Core\Cache\Backend\ApcuBackend;
 use TYPO3\CMS\Core\Cache\Exception;
 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
 use TYPO3\CMS\Core\Utility\StringUtility;
-use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
-use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
 /**
  * NOTE: If you want to execute these tests you need to enable apc in
  * cli context (apc.enable_cli = 1) and disable slam defense (apc.slam_defense = 0)
  */
-class ApcuBackendTest extends UnitTestCase
+class ApcuBackendTest extends FunctionalTestCase
 {
-    protected bool $resetSingletonInstances = true;
+    protected bool $initializeDatabase = false;
 
     protected function setUp(): void
     {
-        parent::setUp();
         // APCu module is called apcu, but options are prefixed with apc
         if (!extension_loaded('apcu') || !(bool)ini_get('apc.enabled') || !(bool)ini_get('apc.enable_cli')) {
             self::markTestSkipped('APCu extension was not available, or it was disabled for CLI.');
         }
-        if ((bool)ini_get('apc.slam_defense')) {
+        if (ini_get('apc.slam_defense')) {
             self::markTestSkipped('This testcase can only be executed with apc.slam_defense = 0');
         }
+        parent::setUp();
+    }
+
+    protected function tearDown(): void
+    {
+        apcu_clear_cache();
+        parent::tearDown();
     }
 
     /**
@@ -62,24 +67,51 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function itIsPossibleToSetAndCheckExistenceInCache(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'Some data';
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
         self::assertTrue($backend->has($identifier));
     }
 
+    public function itIsPossibleToSetAndGetEntryDataProvider(): iterable
+    {
+        yield [ 5 ];
+        yield [ 5.23 ];
+        yield [ 'foo' ];
+        yield [ false ];
+        yield [ true ];
+        yield [ null ];
+        yield [ ['foo', 'bar'] ];
+    }
+
     /**
      * @test
+     * @dataProvider itIsPossibleToSetAndGetEntryDataProvider
      */
-    public function itIsPossibleToSetAndGetEntry(): void
+    public function itIsPossibleToSetAndGetEntry(mixed $data): void
     {
-        $backend = $this->setUpBackend();
-        $data = 'Some data';
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
+        self::assertSame($data, $backend->get($identifier));
+    }
+
+    /**
+     * @test
+     */
+    public function itIsPossibleToSetAndGetObject(): void
+    {
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
+        $identifier = StringUtility::getUniqueId('MyIdentifier');
+        $object = new \stdClass();
+        $object->foo = 'foo';
+        $backend->set($identifier, $object);
         $fetchedData = $backend->get($identifier);
-        self::assertEquals($data, $fetchedData);
+        self::assertEquals($object, $fetchedData);
     }
 
     /**
@@ -87,7 +119,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function itIsPossibleToRemoveEntryFromCache(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'Some data';
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -100,7 +133,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function itIsPossibleToOverwriteAnEntryInTheCache(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'Some data';
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -115,7 +149,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function findIdentifiersByTagFindsSetEntries(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'Some data';
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
@@ -130,7 +165,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function setRemovesTagsFromPreviousSet(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'Some data';
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tagX']);
@@ -144,7 +180,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function hasReturnsFalseIfTheEntryDoesNotExist(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $identifier = StringUtility::getUniqueId('NonExistingIdentifier');
         self::assertFalse($backend->has($identifier));
     }
@@ -154,7 +191,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function removeReturnsFalseIfTheEntryDoesntExist(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $identifier = StringUtility::getUniqueId('NonExistingIdentifier');
         self::assertFalse($backend->remove($identifier));
     }
@@ -164,7 +202,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function flushByTagRemovesCacheEntriesWithSpecifiedTag(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'some data' . microtime();
         $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
         $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
@@ -180,7 +219,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function flushByTagsRemovesCacheEntriesWithSpecifiedTags(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'some data' . microtime();
         $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
         $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
@@ -196,7 +236,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function flushRemovesAllCacheEntries(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = 'some data' . microtime();
         $backend->set('BackendAPCUTest1', $data);
         $backend->set('BackendAPCUTest2', $data);
@@ -235,7 +276,8 @@ class ApcuBackendTest extends UnitTestCase
      */
     public function largeDataIsStored(): void
     {
-        $backend = $this->setUpBackend();
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
         $data = str_repeat('abcde', 1024 * 1024);
         $identifier = StringUtility::getUniqueId('tooLargeData');
         $backend->set($identifier, $data);
@@ -251,35 +293,13 @@ class ApcuBackendTest extends UnitTestCase
         $identifier = StringUtility::getUniqueId('MyIdentifier');
         $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
 
-        $backend = $this->setUpBackend(true);
-        $backend->_call('addIdentifierToTags', $identifier, $tags);
-        self::assertSame(
-            $tags,
-            $backend->_call('findTagsByIdentifier', $identifier)
-        );
-
-        $backend->_call('addIdentifierToTags', $identifier, $tags);
-        self::assertSame(
-            $tags,
-            $backend->_call('findTagsByIdentifier', $identifier)
-        );
-    }
+        $backend = new ApcuBackend('Testing');
+        $backend->setCache($this->createMock(FrontendInterface::class));
+        $backend->set($identifier, 'testData', $tags);
+        $backend->set($identifier, 'testData', $tags);
 
-    /**
-     * Sets up the APCu backend used for testing
-     *
-     * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
-     * @return AccessibleObjectInterface|ApcuBackend
-     */
-    protected function setUpBackend(bool $accessible = false)
-    {
-        $cache = $this->createMock(FrontendInterface::class);
-        if ($accessible) {
-            $backend = $this->getAccessibleMock(ApcuBackend::class, null, ['Testing']);
-        } else {
-            $backend = new ApcuBackend('Testing');
-        }
-        $backend->setCache($cache);
-        return $backend;
+        // Expect exactly 5 entries:
+        // 1 for data, 3 for tag->identifier, 1 for identifier->tags
+        self::assertSame(5, count(apcu_cache_info()['cache_list']));
     }
 }
diff --git a/typo3/sysext/core/Tests/Functional/Cache/Backend/RedisBackendTest.php b/typo3/sysext/core/Tests/Functional/Cache/Backend/RedisBackendTest.php
index 16bbd7fd65aaf769f1746e5acd0323e8e182c839..f0dc7af6731623d29f635ce97576bb2d80278a01 100644
--- a/typo3/sysext/core/Tests/Functional/Cache/Backend/RedisBackendTest.php
+++ b/typo3/sysext/core/Tests/Functional/Cache/Backend/RedisBackendTest.php
@@ -42,10 +42,9 @@ class RedisBackendTest extends FunctionalTestCase
         if (!getenv('typo3TestingRedisHost')) {
             self::markTestSkipped('environment variable "typo3TestingRedisHost" must be set to run this test');
         }
-        // Note we assume that if that typo3TestingRedisHost env is set, we can use that for testing,
+        // Note we assume that if typo3TestingRedisHost env is set, we can use that for testing,
         // there is no test to see if the daemon is actually up and running. Tests will fail if env
         // is set but daemon is down.
-
         parent::setUp();
     }
 
diff --git a/typo3/sysext/core/composer.json b/typo3/sysext/core/composer.json
index 46110237765dfc46e404e36b8f28b6a6aba13db4..6127790262e751c5dcfea1e156c1c7729b42f72b 100644
--- a/typo3/sysext/core/composer.json
+++ b/typo3/sysext/core/composer.json
@@ -76,6 +76,7 @@
 		"typo3fluid/fluid": "^2.7.2"
 	},
 	"suggest": {
+		"ext-apcu": "Needed when non-default APCU based cache backends are used",
 		"ext-fileinfo": "Used for proper file type detection in the file abstraction layer",
 		"ext-gd": "GDlib/Freetype is required for building images with text (GIFBUILDER) and can also be used to scale images",
 		"ext-mysqli": "",