diff --git a/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php b/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php
index 9eea8a9ae0bb08faf0c4a82ff5db46ee2679fe33..83b40ffed1de967c0d91595dd13dfc895009363c 100644
--- a/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php
+++ b/typo3/sysext/backend/Classes/Controller/SiteConfigurationController.php
@@ -34,6 +34,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
@@ -72,6 +73,7 @@ class SiteConfigurationController
         private readonly FormDataCompiler $formDataCompiler,
         private readonly PageRenderer $pageRenderer,
         private readonly SiteConfiguration $siteConfiguration,
+        private readonly SiteWriter $siteWriter,
     ) {}
 
     /**
@@ -402,13 +404,12 @@ class SiteConfigurationController
             );
 
             // Persist the configuration
-            $siteConfigurationManager = GeneralUtility::makeInstance(SiteConfiguration::class);
             try {
                 if (!$isNewConfiguration && $currentIdentifier !== $siteIdentifier) {
-                    $siteConfigurationManager->rename($currentIdentifier, $siteIdentifier);
+                    $this->siteWriter->rename($currentIdentifier, $siteIdentifier);
                     $this->getBackendUser()->writelog(Type::SITE, SiteAction::RENAME, SystemLogErrorClassification::MESSAGE, 0, 'Site configuration \'%s\' was renamed to \'%s\'.', [$currentIdentifier, $siteIdentifier], 'site');
                 }
-                $siteConfigurationManager->write($siteIdentifier, $newSiteConfiguration, true);
+                $this->siteWriter->write($siteIdentifier, $newSiteConfiguration, true);
                 if ($isNewConfiguration) {
                     $this->getBackendUser()->writelog(Type::SITE, SiteAction::CREATE, SystemLogErrorClassification::MESSAGE, 0, 'Site configuration \'%s\' was created.', [$siteIdentifier], 'site');
                 } else {
@@ -656,7 +657,7 @@ class SiteConfigurationController
         }
         try {
             // Verify site does exist, method throws if not
-            GeneralUtility::makeInstance(SiteConfiguration::class)->delete($siteIdentifier);
+            $this->siteWriter->delete($siteIdentifier);
             $this->getBackendUser()->writelog(Type::SITE, SiteAction::DELETE, SystemLogErrorClassification::MESSAGE, 0, 'Site configuration \'%s\' was deleted.', [$siteIdentifier], 'site');
         } catch (SiteConfigurationWriteException $e) {
             $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $e->getMessage(), '', ContextualFeedbackSeverity::WARNING, true);
diff --git a/typo3/sysext/core/Classes/Configuration/Event/SiteConfigurationChangedEvent.php b/typo3/sysext/core/Classes/Configuration/Event/SiteConfigurationChangedEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..264052de11bda2cf3277aacafab0e61af6002484
--- /dev/null
+++ b/typo3/sysext/core/Classes/Configuration/Event/SiteConfigurationChangedEvent.php
@@ -0,0 +1,28 @@
+<?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\Configuration\Event;
+
+/**
+ * @internal
+ */
+final readonly class SiteConfigurationChangedEvent
+{
+    public function __construct(
+        public string $siteIdentifier,
+    ) {}
+}
diff --git a/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php b/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
index fc3f084ad31dd199681e5c631094b2ccde44f8c7..91a5eeb13838ae4c21b97cfcab525d524d43e274 100644
--- a/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
+++ b/typo3/sysext/core/Classes/Configuration/SiteConfiguration.php
@@ -18,22 +18,19 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Core\Configuration;
 
 use Psr\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
 use Symfony\Component\Finder\Finder;
 use Symfony\Component\Yaml\Yaml;
+use TYPO3\CMS\Core\Attribute\AsEventListener;
 use TYPO3\CMS\Core\Cache\Event\CacheWarmupEvent;
 use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
-use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationBeforeWriteEvent;
+use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationChangedEvent;
 use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationLoadedEvent;
-use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
-use TYPO3\CMS\Core\Configuration\Loader\Exception\YamlPlaceholderException;
 use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
-use TYPO3\CMS\Core\Configuration\Loader\YamlPlaceholderGuard;
-use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Site\Entity\Site;
 use TYPO3\CMS\Core\Site\Entity\SiteSettings;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -82,8 +79,10 @@ class SiteConfiguration implements SingletonInterface
     protected $firstLevelCache;
 
     public function __construct(
+        #[Autowire('%env(TYPO3:configPath)%/sites')]
         protected string $configPath,
         protected EventDispatcherInterface $eventDispatcher,
+        #[Autowire(service: 'cache.core')]
         protected PhpFrontend $cache
     ) {}
 
@@ -100,33 +99,6 @@ class SiteConfiguration implements SingletonInterface
         return $this->resolveAllExistingSites($useCache);
     }
 
-    /**
-     * Creates a site configuration with one language "English" which is the de-facto default language for TYPO3 in general.
-     *
-     * @throws SiteConfigurationWriteException
-     */
-    public function createNewBasicSite(string $identifier, int $rootPageId, string $base): void
-    {
-        // Create a default site configuration called "main" as best practice
-        $this->write($identifier, [
-            'rootPageId' => $rootPageId,
-            'base' => $base,
-            'languages' => [
-                0 => [
-                    'title' => 'English',
-                    'enabled' => true,
-                    'languageId' => 0,
-                    'base' => '/',
-                    'locale' => 'en_US.UTF-8',
-                    'navigationTitle' => 'English',
-                    'flag' => 'us',
-                ],
-            ],
-            'errorHandling' => [],
-            'routes' => [],
-        ]);
-    }
-
     /**
      * Resolve all site objects which have been found in the filesystem.
      *
@@ -277,163 +249,13 @@ class SiteConfiguration implements SingletonInterface
         return [];
     }
 
-    public function writeSettings(string $siteIdentifier, array $settings): void
-    {
-        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->settingsFileName;
-        $yamlFileContents = Yaml::dump($settings, 99, 2);
-        if (!GeneralUtility::writeFile($fileName, $yamlFileContents)) {
-            throw new SiteConfigurationWriteException('Unable to write site settings in sites/' . $siteIdentifier . '/' . $this->configFileName, 1590487411);
-        }
-    }
-
-    /**
-     * Add or update a site configuration
-     *
-     * @param bool $protectPlaceholders whether to disallow introducing new placeholders
-     * @todo enforce $protectPlaceholders with TYPO3 v13.0
-     * @throws SiteConfigurationWriteException
-     */
-    public function write(string $siteIdentifier, array $configuration, bool $protectPlaceholders = false): void
+    #[AsEventListener(event: SiteConfigurationChangedEvent::class)]
+    public function siteConfigurationChanged()
     {
-        $folder = $this->configPath . '/' . $siteIdentifier;
-        $fileName = $folder . '/' . $this->configFileName;
-        $newConfiguration = $configuration;
-        if (!file_exists($folder)) {
-            GeneralUtility::mkdir_deep($folder);
-            if ($protectPlaceholders && $newConfiguration !== []) {
-                $newConfiguration = $this->protectPlaceholders([], $newConfiguration);
-            }
-        } elseif (file_exists($fileName)) {
-            $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
-            // load without any processing to have the unprocessed base to modify
-            $newConfiguration = $loader->load(GeneralUtility::fixWindowsFilePath($fileName), 0);
-            // load the processed configuration to diff changed values
-            $processed = $loader->load(GeneralUtility::fixWindowsFilePath($fileName));
-            // find properties that were modified via GUI
-            $newModified = array_replace_recursive(
-                self::findRemoved($processed, $configuration),
-                self::findModified($processed, $configuration)
-            );
-            if ($protectPlaceholders && $newModified !== []) {
-                $newModified = $this->protectPlaceholders($newConfiguration, $newModified);
-            }
-            // change _only_ the modified keys, leave the original non-changed areas alone
-            ArrayUtility::mergeRecursiveWithOverrule($newConfiguration, $newModified);
-        }
-        $event = $this->eventDispatcher->dispatch(new SiteConfigurationBeforeWriteEvent($siteIdentifier, $newConfiguration));
-        $newConfiguration = $this->sortConfiguration($event->getConfiguration());
-        $yamlFileContents = Yaml::dump($newConfiguration, 99, 2);
-        if (!GeneralUtility::writeFile($fileName, $yamlFileContents)) {
-            throw new SiteConfigurationWriteException('Unable to write site configuration in sites/' . $siteIdentifier . '/' . $this->configFileName, 1590487011);
-        }
         $this->firstLevelCache = null;
-        $this->cache->remove($this->cacheIdentifier);
-    }
-
-    /**
-     * Renames a site identifier (and moves the folder)
-     *
-     * @throws SiteConfigurationWriteException
-     */
-    public function rename(string $currentIdentifier, string $newIdentifier): void
-    {
-        if (!rename($this->configPath . '/' . $currentIdentifier, $this->configPath . '/' . $newIdentifier)) {
-            throw new SiteConfigurationWriteException('Unable to rename folder sites/' . $currentIdentifier, 1522491300);
-        }
-        $this->cache->remove($this->cacheIdentifier);
-        $this->firstLevelCache = null;
-    }
-
-    /**
-     * Removes the config.yaml file of a site configuration.
-     * Also clears the cache.
-     *
-     * @throws SiteNotFoundException|SiteConfigurationWriteException
-     */
-    public function delete(string $siteIdentifier): void
-    {
-        $sites = $this->getAllExistingSites();
-        if (!isset($sites[$siteIdentifier])) {
-            throw new SiteNotFoundException('Site configuration named ' . $siteIdentifier . ' not found.', 1522866183);
-        }
-        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
-        if (!file_exists($fileName)) {
-            throw new SiteNotFoundException('Site configuration file ' . $this->configFileName . ' within the site ' . $siteIdentifier . ' not found.', 1522866184);
-        }
-        if (!unlink($fileName)) {
-            throw new SiteConfigurationWriteException('Unable to delete folder sites/' . $siteIdentifier, 1596462020);
-        }
-        $this->cache->remove($this->cacheIdentifier);
-        $this->firstLevelCache = null;
-    }
-
-    /**
-     * Detects placeholders that have been introduced and handles* them.
-     * (*) currently throws an exception, but could be purged or escaped as well
-     *
-     * @param array<string, mixed> $existingConfiguration
-     * @param array<string, mixed> $modifiedConfiguration
-     * @return array<string, mixed> sanitized configuration (currently not used, exception thrown before)
-     * @throws SiteConfigurationWriteException
-     */
-    protected function protectPlaceholders(array $existingConfiguration, array $modifiedConfiguration): array
-    {
-        try {
-            return GeneralUtility::makeInstance(YamlPlaceholderGuard::class, $existingConfiguration)
-                ->process($modifiedConfiguration);
-        } catch (YamlPlaceholderException $exception) {
-            throw new SiteConfigurationWriteException($exception->getMessage(), 1670361271, $exception);
-        }
-    }
-
-    protected function sortConfiguration(array $newConfiguration): array
-    {
-        ksort($newConfiguration);
-        if (isset($newConfiguration['imports'])) {
-            $imports = $newConfiguration['imports'];
-            unset($newConfiguration['imports']);
-            $newConfiguration['imports'] = $imports;
-        }
-        return $newConfiguration;
-    }
-
-    protected static function findModified(array $currentConfiguration, array $newConfiguration): array
-    {
-        $differences = [];
-        foreach ($newConfiguration as $key => $value) {
-            if (!isset($currentConfiguration[$key]) || $currentConfiguration[$key] !== $newConfiguration[$key]) {
-                if (!isset($newConfiguration[$key]) && isset($currentConfiguration[$key])) {
-                    $differences[$key] = '__UNSET';
-                } elseif (isset($currentConfiguration[$key])
-                    && is_array($newConfiguration[$key])
-                    && is_array($currentConfiguration[$key])
-                ) {
-                    $differences[$key] = self::findModified($currentConfiguration[$key], $newConfiguration[$key]);
-                } else {
-                    $differences[$key] = $value;
-                }
-            }
-        }
-        return $differences;
-    }
-
-    protected static function findRemoved(array $currentConfiguration, array $newConfiguration): array
-    {
-        $removed = [];
-        foreach ($currentConfiguration as $key => $value) {
-            if (!isset($newConfiguration[$key])) {
-                $removed[$key] = '__UNSET';
-            } elseif (isset($currentConfiguration[$key]) && is_array($currentConfiguration[$key]) && is_array($newConfiguration[$key])) {
-                $removedInRecursion = self::findRemoved($currentConfiguration[$key], $newConfiguration[$key]);
-                if (!empty($removedInRecursion)) {
-                    $removed[$key] = $removedInRecursion;
-                }
-            }
-        }
-
-        return $removed;
     }
 
+    #[AsEventListener('typo3-core/site-configuration')]
     public function warmupCaches(CacheWarmupEvent $event): void
     {
         if ($event->hasGroup('system')) {
diff --git a/typo3/sysext/core/Classes/Configuration/SiteWriter.php b/typo3/sysext/core/Classes/Configuration/SiteWriter.php
new file mode 100644
index 0000000000000000000000000000000000000000..98e951e34f6e2d21003030f6d7dd1523c9e581a3
--- /dev/null
+++ b/typo3/sysext/core/Classes/Configuration/SiteWriter.php
@@ -0,0 +1,247 @@
+<?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\Configuration;
+
+use Psr\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Yaml\Yaml;
+use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
+use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationBeforeWriteEvent;
+use TYPO3\CMS\Core\Configuration\Event\SiteConfigurationChangedEvent;
+use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
+use TYPO3\CMS\Core\Configuration\Loader\Exception\YamlPlaceholderException;
+use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
+use TYPO3\CMS\Core\Configuration\Loader\YamlPlaceholderGuard;
+use TYPO3\CMS\Core\Exception\SiteNotFoundException;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Writes Site objects into site configuration files.
+ *
+ * @internal
+ */
+class SiteWriter
+{
+    /**
+     * Config yaml file name.
+     *
+     * @internal
+     */
+    protected string $configFileName = 'config.yaml';
+
+    /**
+     * YAML file name with all settings.
+     *
+     * @internal
+     * @todo remove, move usages to SiteSettingsFactory
+     */
+    protected string $settingsFileName = 'settings.yaml';
+
+    /**
+     * Identifier to store all configuration data in the core cache.
+     *
+     * @internal
+     */
+    protected string $cacheIdentifier = 'sites-configuration';
+
+    public function __construct(
+        protected string $configPath,
+        protected EventDispatcherInterface $eventDispatcher,
+        protected PhpFrontend $cache
+    ) {}
+
+    /**
+     * Creates a site configuration with one language "English" which is the de-facto default language for TYPO3 in general.
+     *
+     * @throws SiteConfigurationWriteException
+     */
+    public function createNewBasicSite(string $identifier, int $rootPageId, string $base): void
+    {
+        // Create a default site configuration called "main" as best practice
+        $this->write($identifier, [
+            'rootPageId' => $rootPageId,
+            'base' => $base,
+            'languages' => [
+                0 => [
+                    'title' => 'English',
+                    'enabled' => true,
+                    'languageId' => 0,
+                    'base' => '/',
+                    'locale' => 'en_US.UTF-8',
+                    'navigationTitle' => 'English',
+                    'flag' => 'us',
+                ],
+            ],
+            'errorHandling' => [],
+            'routes' => [],
+        ]);
+    }
+
+    public function writeSettings(string $siteIdentifier, array $settings): void
+    {
+        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->settingsFileName;
+        $yamlFileContents = Yaml::dump($settings, 99, 2);
+        if (!GeneralUtility::writeFile($fileName, $yamlFileContents)) {
+            throw new SiteConfigurationWriteException('Unable to write site settings in sites/' . $siteIdentifier . '/' . $this->configFileName, 1590487411);
+        }
+    }
+
+    /**
+     * Add or update a site configuration
+     *
+     * @param bool $protectPlaceholders whether to disallow introducing new placeholders
+     * @todo enforce $protectPlaceholders with TYPO3 v13.0
+     * @throws SiteConfigurationWriteException
+     */
+    public function write(string $siteIdentifier, array $configuration, bool $protectPlaceholders = false): void
+    {
+        $folder = $this->configPath . '/' . $siteIdentifier;
+        $fileName = $folder . '/' . $this->configFileName;
+        $newConfiguration = $configuration;
+        if (!file_exists($folder)) {
+            GeneralUtility::mkdir_deep($folder);
+            if ($protectPlaceholders && $newConfiguration !== []) {
+                $newConfiguration = $this->protectPlaceholders([], $newConfiguration);
+            }
+        } elseif (file_exists($fileName)) {
+            $loader = GeneralUtility::makeInstance(YamlFileLoader::class);
+            // load without any processing to have the unprocessed base to modify
+            $newConfiguration = $loader->load(GeneralUtility::fixWindowsFilePath($fileName), 0);
+            // load the processed configuration to diff changed values
+            $processed = $loader->load(GeneralUtility::fixWindowsFilePath($fileName));
+            // find properties that were modified via GUI
+            $newModified = array_replace_recursive(
+                self::findRemoved($processed, $configuration),
+                self::findModified($processed, $configuration)
+            );
+            if ($protectPlaceholders && $newModified !== []) {
+                $newModified = $this->protectPlaceholders($newConfiguration, $newModified);
+            }
+            // change _only_ the modified keys, leave the original non-changed areas alone
+            ArrayUtility::mergeRecursiveWithOverrule($newConfiguration, $newModified);
+        }
+        $event = $this->eventDispatcher->dispatch(new SiteConfigurationBeforeWriteEvent($siteIdentifier, $newConfiguration));
+        $newConfiguration = $this->sortConfiguration($event->getConfiguration());
+        $yamlFileContents = Yaml::dump($newConfiguration, 99, 2);
+        if (!GeneralUtility::writeFile($fileName, $yamlFileContents)) {
+            throw new SiteConfigurationWriteException('Unable to write site configuration in sites/' . $siteIdentifier . '/' . $this->configFileName, 1590487011);
+        }
+        $this->cache->remove($this->cacheIdentifier);
+        $this->eventDispatcher->dispatch(new SiteConfigurationChangedEvent($siteIdentifier));
+    }
+
+    /**
+     * Renames a site identifier (and moves the folder)
+     *
+     * @throws SiteConfigurationWriteException
+     */
+    public function rename(string $currentIdentifier, string $newIdentifier): void
+    {
+        if (!rename($this->configPath . '/' . $currentIdentifier, $this->configPath . '/' . $newIdentifier)) {
+            throw new SiteConfigurationWriteException('Unable to rename folder sites/' . $currentIdentifier, 1522491300);
+        }
+        $this->cache->remove($this->cacheIdentifier);
+        $this->eventDispatcher->dispatch(new SiteConfigurationChangedEvent($newIdentifier));
+    }
+
+    /**
+     * Removes the config.yaml file of a site configuration.
+     * Also clears the cache.
+     *
+     * @throws SiteNotFoundException|SiteConfigurationWriteException
+     */
+    public function delete(string $siteIdentifier): void
+    {
+        $fileName = $this->configPath . '/' . $siteIdentifier . '/' . $this->configFileName;
+        if (!file_exists($fileName)) {
+            throw new SiteNotFoundException('Site configuration file ' . $this->configFileName . ' within the site ' . $siteIdentifier . ' not found.', 1522866184);
+        }
+        if (!unlink($fileName)) {
+            throw new SiteConfigurationWriteException('Unable to delete folder sites/' . $siteIdentifier, 1596462020);
+        }
+        $this->cache->remove($this->cacheIdentifier);
+        $this->eventDispatcher->dispatch(new SiteConfigurationChangedEvent($siteIdentifier));
+    }
+
+    /**
+     * Detects placeholders that have been introduced and handles* them.
+     * (*) currently throws an exception, but could be purged or escaped as well
+     *
+     * @param array<string, mixed> $existingConfiguration
+     * @param array<string, mixed> $modifiedConfiguration
+     * @return array<string, mixed> sanitized configuration (currently not used, exception thrown before)
+     * @throws SiteConfigurationWriteException
+     */
+    protected function protectPlaceholders(array $existingConfiguration, array $modifiedConfiguration): array
+    {
+        try {
+            return GeneralUtility::makeInstance(YamlPlaceholderGuard::class, $existingConfiguration)
+                ->process($modifiedConfiguration);
+        } catch (YamlPlaceholderException $exception) {
+            throw new SiteConfigurationWriteException($exception->getMessage(), 1670361271, $exception);
+        }
+    }
+
+    protected function sortConfiguration(array $newConfiguration): array
+    {
+        ksort($newConfiguration);
+        if (isset($newConfiguration['imports'])) {
+            $imports = $newConfiguration['imports'];
+            unset($newConfiguration['imports']);
+            $newConfiguration['imports'] = $imports;
+        }
+        return $newConfiguration;
+    }
+
+    protected static function findModified(array $currentConfiguration, array $newConfiguration): array
+    {
+        $differences = [];
+        foreach ($newConfiguration as $key => $value) {
+            if (!isset($currentConfiguration[$key]) || $currentConfiguration[$key] !== $newConfiguration[$key]) {
+                if (!isset($newConfiguration[$key]) && isset($currentConfiguration[$key])) {
+                    $differences[$key] = '__UNSET';
+                } elseif (isset($currentConfiguration[$key])
+                    && is_array($newConfiguration[$key])
+                    && is_array($currentConfiguration[$key])
+                ) {
+                    $differences[$key] = self::findModified($currentConfiguration[$key], $newConfiguration[$key]);
+                } else {
+                    $differences[$key] = $value;
+                }
+            }
+        }
+        return $differences;
+    }
+
+    protected static function findRemoved(array $currentConfiguration, array $newConfiguration): array
+    {
+        $removed = [];
+        foreach ($currentConfiguration as $key => $value) {
+            if (!isset($newConfiguration[$key])) {
+                $removed[$key] = '__UNSET';
+            } elseif (isset($currentConfiguration[$key]) && is_array($currentConfiguration[$key]) && is_array($newConfiguration[$key])) {
+                $removedInRecursion = self::findRemoved($currentConfiguration[$key], $newConfiguration[$key]);
+                if (!empty($removedInRecursion)) {
+                    $removed[$key] = $removedInRecursion;
+                }
+            }
+        }
+
+        return $removed;
+    }
+}
diff --git a/typo3/sysext/core/Classes/Hooks/CreateSiteConfiguration.php b/typo3/sysext/core/Classes/Hooks/CreateSiteConfiguration.php
index 882eb61b965b83a2eca19f7a110283dd4bf962c8..aaa137d96105b8b3d71d132d5b9bf8f15dd67ba8 100644
--- a/typo3/sysext/core/Classes/Hooks/CreateSiteConfiguration.php
+++ b/typo3/sysext/core/Classes/Hooks/CreateSiteConfiguration.php
@@ -19,7 +19,7 @@ namespace TYPO3\CMS\Core\Hooks;
 
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
@@ -87,11 +87,11 @@ class CreateSiteConfiguration
         $siteIdentifier = $entryPoint . '-' . md5((string)$pageId);
 
         if (!$this->siteExistsByRootPageId($pageId)) {
-            $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
+            $siteWriter = GeneralUtility::makeInstance(SiteWriter::class);
             $normalizedParams = $this->getNormalizedParams();
             $basePrefix = Environment::isCli() ? $normalizedParams->getSitePath() : $normalizedParams->getSiteUrl();
             try {
-                $siteConfiguration->createNewBasicSite(
+                $siteWriter->createNewBasicSite(
                     $siteIdentifier,
                     $pageId,
                     $basePrefix . $entryPoint
diff --git a/typo3/sysext/core/Classes/ServiceProvider.php b/typo3/sysext/core/Classes/ServiceProvider.php
index 44cf4125dca30cbe5809acf168eefedf225bc62d..e24c81bcf79053db5599c4ec5c71aa376866eaee 100644
--- a/typo3/sysext/core/Classes/ServiceProvider.php
+++ b/typo3/sysext/core/Classes/ServiceProvider.php
@@ -59,7 +59,7 @@ class ServiceProvider extends AbstractServiceProvider
             Database\DriverMiddlewareService::class => self::getDriverMiddlewaresService(...),
             Charset\CharsetConverter::class => self::getCharsetConverter(...),
             Configuration\Loader\YamlFileLoader::class => self::getYamlFileLoader(...),
-            Configuration\SiteConfiguration::class => self::getSiteConfiguration(...),
+            Configuration\SiteWriter::class => self::getSiteWriter(...),
             Command\ListCommand::class => self::getListCommand(...),
             HelpCommand::class => self::getHelpCommand(...),
             Command\CacheFlushCommand::class => self::getCacheFlushCommand(...),
@@ -184,9 +184,9 @@ class ServiceProvider extends AbstractServiceProvider
         return self::new($container, Configuration\Loader\YamlFileLoader::class);
     }
 
-    public static function getSiteConfiguration(ContainerInterface $container): Configuration\SiteConfiguration
+    public static function getSiteWriter(ContainerInterface $container): Configuration\SiteWriter
     {
-        return self::new($container, Configuration\SiteConfiguration::class, [
+        return self::new($container, Configuration\SiteWriter::class, [
             Environment::getConfigPath() . '/sites',
             $container->get(EventDispatcherInterface::class),
             $container->get('cache.core'),
@@ -269,7 +269,6 @@ class ServiceProvider extends AbstractServiceProvider
         );
 
         $cacheWarmers = [
-            Configuration\SiteConfiguration::class,
             Http\MiddlewareStackResolver::class,
             Imaging\IconRegistry::class,
             Package\PackageManager::class,
diff --git a/typo3/sysext/core/Configuration/Services.yaml b/typo3/sysext/core/Configuration/Services.yaml
index 138be5a334626967dfe5720e17f0c2bc06e71f76..55091672a1bc17624643fafda80a477d72a1f9fc 100644
--- a/typo3/sysext/core/Configuration/Services.yaml
+++ b/typo3/sysext/core/Configuration/Services.yaml
@@ -56,11 +56,6 @@ services:
   TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools:
     public: true
 
-  TYPO3\CMS\Core\Configuration\SiteConfiguration:
-    arguments:
-      $cache: '@cache.core'
-      $configPath: '%env(TYPO3:configPath)%/sites'
-
   TYPO3\CMS\Core\Package\UnitTestPackageManager:
     autoconfigure: false
 
diff --git a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
index bc8f79d14366d1faabb49bf992b621e3bfb210a1..568cec75a7da8dab6b8074b39dfb2895fa8fd010 100644
--- a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
+++ b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedAliasMapperTest.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Core\Tests\Functional\Routing\Aspect;
 use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\Attributes\Test;
 use Psr\EventDispatcher\EventDispatcherInterface;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Context\DateTimeAspect;
 use TYPO3\CMS\Core\Context\UserAspect;
@@ -309,7 +309,7 @@ final class PersistedAliasMapperTest extends FunctionalTestCase
             $cache = $this->get('cache.core');
             $eventDispatcher = $this->get(EventDispatcherInterface::class);
             GeneralUtility::rmdir($path . '/' . $site->getIdentifier(), true);
-            GeneralUtility::makeInstance(SiteConfiguration::class, $path, $eventDispatcher, $cache)->write($site->getIdentifier(), $site->getConfiguration());
+            GeneralUtility::makeInstance(SiteWriter::class, $path, $eventDispatcher, $cache)->write($site->getIdentifier(), $site->getConfiguration());
         } catch (\Exception $exception) {
             self::markTestSkipped($exception->getMessage());
         }
diff --git a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedPatternMapperTest.php b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedPatternMapperTest.php
index 66e9169c843dd107c58b18279f3c9557ab902fca..568f1bb68e32a9814f6206ccf9f15c460f4f601b 100644
--- a/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedPatternMapperTest.php
+++ b/typo3/sysext/core/Tests/Functional/Routing/Aspect/PersistedPatternMapperTest.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Core\Tests\Functional\Routing\Aspect;
 use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\Attributes\Test;
 use Psr\EventDispatcher\EventDispatcherInterface;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Context\DateTimeAspect;
 use TYPO3\CMS\Core\Context\UserAspect;
@@ -317,7 +317,7 @@ final class PersistedPatternMapperTest extends FunctionalTestCase
             $cache = $this->get('cache.core');
             $eventDispatcher = $this->get(EventDispatcherInterface::class);
             GeneralUtility::rmdir($path . '/' . $site->getIdentifier(), true);
-            GeneralUtility::makeInstance(SiteConfiguration::class, $path, $eventDispatcher, $cache)->write($site->getIdentifier(), $site->getConfiguration());
+            GeneralUtility::makeInstance(SiteWriter::class, $path, $eventDispatcher, $cache)->write($site->getIdentifier(), $site->getConfiguration());
         } catch (\Exception $exception) {
             self::markTestSkipped($exception->getMessage());
         }
diff --git a/typo3/sysext/core/Tests/Functional/SiteHandling/SiteBasedTestTrait.php b/typo3/sysext/core/Tests/Functional/SiteHandling/SiteBasedTestTrait.php
index 0b8c55a1fb0fc223a319a3824d5c76449c67f4ba..81a6ab09e5a37f741a3c1bc8c2894c15dbef870d 100644
--- a/typo3/sysext/core/Tests/Functional/SiteHandling/SiteBasedTestTrait.php
+++ b/typo3/sysext/core/Tests/Functional/SiteHandling/SiteBasedTestTrait.php
@@ -18,6 +18,7 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Core\Tests\Functional\SiteHandling;
 
 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Tests\Functional\Fixtures\Frontend\PhpError;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\AbstractInstruction;
@@ -59,11 +60,11 @@ trait SiteBasedTestTrait
         if (!empty($errorHandling)) {
             $configuration['errorHandling'] = $errorHandling;
         }
-        $siteConfiguration = $this->get(SiteConfiguration::class);
+        $siteWriter = $this->get(SiteWriter::class);
         try {
             // ensure no previous site configuration influences the test
             GeneralUtility::rmdir($this->instancePath . '/typo3conf/sites/' . $identifier, true);
-            $siteConfiguration->write($identifier, $configuration);
+            $siteWriter->write($identifier, $configuration);
         } catch (\Exception $exception) {
             $this->markTestSkipped($exception->getMessage());
         }
@@ -74,10 +75,11 @@ trait SiteBasedTestTrait
         array $overrides
     ): void {
         $siteConfiguration = $this->get(SiteConfiguration::class);
+        $siteWriter = $this->get(SiteWriter::class);
         $configuration = $siteConfiguration->load($identifier);
         $configuration = array_merge($configuration, $overrides);
         try {
-            $siteConfiguration->write($identifier, $configuration);
+            $siteWriter->write($identifier, $configuration);
         } catch (\Exception $exception) {
             $this->markTestSkipped($exception->getMessage());
         }
diff --git a/typo3/sysext/core/Tests/Unit/Configuration/SiteConfigurationTest.php b/typo3/sysext/core/Tests/Unit/Configuration/SiteConfigurationTest.php
index eb00bcc3cd0b774b649b6d7fcc573b043eb1ca84..c02f46f10b817d1cb590acfa714dee90ad95f495 100644
--- a/typo3/sysext/core/Tests/Unit/Configuration/SiteConfigurationTest.php
+++ b/typo3/sysext/core/Tests/Unit/Configuration/SiteConfigurationTest.php
@@ -17,12 +17,9 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Core\Tests\Unit\Configuration;
 
-use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\Attributes\Test;
 use Symfony\Component\Yaml\Yaml;
 use TYPO3\CMS\Core\Cache\Frontend\NullFrontend;
-use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
-use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\EventDispatcher\NoopEventDispatcher;
@@ -80,110 +77,4 @@ final class SiteConfigurationTest extends UnitTestCase
         self::assertSame(42, $currentSite->getRootPageId());
         self::assertEquals(new Uri('https://example.com'), $currentSite->getBase());
     }
-
-    #[Test]
-    public function writeOnlyWritesModifiedKeys(): void
-    {
-        $identifier = 'testsite';
-        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
-        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config1.yaml';
-        $expected = __DIR__ . '/Fixtures/SiteConfigs/config1_expected.yaml';
-        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
-        copy($configFixture, $siteConfig);
-
-        // load with resolved imports as the module does
-        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
-            ->load(
-                GeneralUtility::fixWindowsFilePath($siteConfig),
-                YamlFileLoader::PROCESS_IMPORTS
-            );
-        // modify something on base level
-        $configuration['base'] = 'https://example.net/';
-        // modify something nested
-        $configuration['languages'][0]['title'] = 'English';
-        // delete values
-        unset($configuration['someOtherValue'], $configuration['languages'][1]);
-
-        $this->siteConfiguration->write($identifier, $configuration, true);
-
-        // expect modified base but intact imports
-        self::assertFileEquals($expected, $siteConfig);
-    }
-
-    #[Test]
-    public function writingOfNestedStructuresPreservesOrder(): void
-    {
-        $identifier = 'testsite';
-        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
-        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config2.yaml';
-        $expected = __DIR__ . '/Fixtures/SiteConfigs/config2_expected.yaml';
-        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
-        copy($configFixture, $siteConfig);
-
-        // load with resolved imports as the module does
-        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
-            ->load(
-                GeneralUtility::fixWindowsFilePath($siteConfig),
-                YamlFileLoader::PROCESS_IMPORTS
-            );
-        // add new language
-        $languageConfig = [
-            'title' => 'English',
-            'enabled' => true,
-            'languageId' => '0',
-            'base' => '/en',
-            'locale' => 'en_US.utf8',
-            'flag' => 'en',
-            'navigationTitle' => 'English',
-        ];
-        array_unshift($configuration['languages'], $languageConfig);
-        $this->siteConfiguration->write($identifier, $configuration, true);
-
-        // expect modified base but intact imports
-        self::assertFileEquals($expected, $siteConfig);
-    }
-
-    public static function writingPlaceholdersIsHandledDataProvider(): \Generator
-    {
-        yield 'unchanged' => [
-            ['customProperty' => 'Using %env("existing")% variable'],
-            false,
-        ];
-        yield 'removed placeholder variable' => [
-            ['customProperty' => 'Not using any variable'],
-            false,
-        ];
-        yield 'changed raw text only' => [
-            ['customProperty' => 'Using %env("existing")% variable from system environment'],
-            false,
-        ];
-        yield 'added new placeholder variable' => [
-            ['customProperty' => 'Using %env("existing")% and %env("secret")% variable'],
-            true,
-        ];
-    }
-
-    #[DataProvider('writingPlaceholdersIsHandledDataProvider')]
-    #[Test]
-    public function writingPlaceholdersIsHandled(array $changes, bool $expectedException): void
-    {
-        if ($expectedException) {
-            $this->expectException(SiteConfigurationWriteException::class);
-            $this->expectExceptionCode(1670361271);
-        }
-
-        $identifier = 'testsite';
-        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
-        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config2.yaml';
-        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
-        copy($configFixture, $siteConfig);
-        // load with resolved imports as the module does
-        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
-            ->load(
-                GeneralUtility::fixWindowsFilePath($siteConfig),
-                YamlFileLoader::PROCESS_IMPORTS
-            );
-        $configuration = array_merge($configuration, $changes);
-        $this->siteConfiguration->write($identifier, $configuration, true);
-    }
 }
diff --git a/typo3/sysext/core/Tests/Unit/Configuration/SiteWriterTest.php b/typo3/sysext/core/Tests/Unit/Configuration/SiteWriterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..df8cae6f2f2043f5cf4019a725d4e9098786640f
--- /dev/null
+++ b/typo3/sysext/core/Tests/Unit/Configuration/SiteWriterTest.php
@@ -0,0 +1,164 @@
+<?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\Configuration;
+
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Test;
+use TYPO3\CMS\Core\Cache\Frontend\NullFrontend;
+use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
+use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
+use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\EventDispatcher\NoopEventDispatcher;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+final class SiteWriterTest extends UnitTestCase
+{
+    protected bool $resetSingletonInstances = true;
+
+    protected ?SiteWriter $siteWriter;
+
+    /**
+     * store temporarily used files here
+     * will be removed after each test
+     */
+    protected ?string $fixturePath;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $basePath = Environment::getVarPath() . '/tests/unit';
+        $this->fixturePath = $basePath . '/fixture/config/sites';
+        if (!file_exists($this->fixturePath)) {
+            GeneralUtility::mkdir_deep($this->fixturePath);
+        }
+        $this->testFilesToDelete[] = $basePath;
+        $this->siteWriter = new SiteWriter(
+            $this->fixturePath,
+            new NoopEventDispatcher(),
+            new NullFrontend('test')
+        );
+    }
+
+    #[Test]
+    public function writeOnlyWritesModifiedKeys(): void
+    {
+        $identifier = 'testsite';
+        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
+        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config1.yaml';
+        $expected = __DIR__ . '/Fixtures/SiteConfigs/config1_expected.yaml';
+        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
+        copy($configFixture, $siteConfig);
+
+        // load with resolved imports as the module does
+        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
+            ->load(
+                GeneralUtility::fixWindowsFilePath($siteConfig),
+                YamlFileLoader::PROCESS_IMPORTS
+            );
+        // modify something on base level
+        $configuration['base'] = 'https://example.net/';
+        // modify something nested
+        $configuration['languages'][0]['title'] = 'English';
+        // delete values
+        unset($configuration['someOtherValue'], $configuration['languages'][1]);
+
+        $this->siteWriter->write($identifier, $configuration, true);
+
+        // expect modified base but intact imports
+        self::assertFileEquals($expected, $siteConfig);
+    }
+
+    #[Test]
+    public function writingOfNestedStructuresPreservesOrder(): void
+    {
+        $identifier = 'testsite';
+        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
+        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config2.yaml';
+        $expected = __DIR__ . '/Fixtures/SiteConfigs/config2_expected.yaml';
+        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
+        copy($configFixture, $siteConfig);
+
+        // load with resolved imports as the module does
+        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
+            ->load(
+                GeneralUtility::fixWindowsFilePath($siteConfig),
+                YamlFileLoader::PROCESS_IMPORTS
+            );
+        // add new language
+        $languageConfig = [
+            'title' => 'English',
+            'enabled' => true,
+            'languageId' => '0',
+            'base' => '/en',
+            'locale' => 'en_US.utf8',
+            'flag' => 'en',
+            'navigationTitle' => 'English',
+        ];
+        array_unshift($configuration['languages'], $languageConfig);
+        $this->siteWriter->write($identifier, $configuration, true);
+
+        // expect modified base but intact imports
+        self::assertFileEquals($expected, $siteConfig);
+    }
+
+    public static function writingPlaceholdersIsHandledDataProvider(): \Generator
+    {
+        yield 'unchanged' => [
+            ['customProperty' => 'Using %env("existing")% variable'],
+            false,
+        ];
+        yield 'removed placeholder variable' => [
+            ['customProperty' => 'Not using any variable'],
+            false,
+        ];
+        yield 'changed raw text only' => [
+            ['customProperty' => 'Using %env("existing")% variable from system environment'],
+            false,
+        ];
+        yield 'added new placeholder variable' => [
+            ['customProperty' => 'Using %env("existing")% and %env("secret")% variable'],
+            true,
+        ];
+    }
+
+    #[DataProvider('writingPlaceholdersIsHandledDataProvider')]
+    #[Test]
+    public function writingPlaceholdersIsHandled(array $changes, bool $expectedException): void
+    {
+        if ($expectedException) {
+            $this->expectException(SiteConfigurationWriteException::class);
+            $this->expectExceptionCode(1670361271);
+        }
+
+        $identifier = 'testsite';
+        GeneralUtility::mkdir_deep($this->fixturePath . '/' . $identifier);
+        $configFixture = __DIR__ . '/Fixtures/SiteConfigs/config2.yaml';
+        $siteConfig = $this->fixturePath . '/' . $identifier . '/config.yaml';
+        copy($configFixture, $siteConfig);
+        // load with resolved imports as the module does
+        $configuration = GeneralUtility::makeInstance(YamlFileLoader::class)
+            ->load(
+                GeneralUtility::fixWindowsFilePath($siteConfig),
+                YamlFileLoader::PROCESS_IMPORTS
+            );
+        $configuration = array_merge($configuration, $changes);
+        $this->siteWriter->write($identifier, $configuration, true);
+    }
+}
diff --git a/typo3/sysext/impexp/Classes/Initialization/ImportSiteConfigurationsOnPackageInitialization.php b/typo3/sysext/impexp/Classes/Initialization/ImportSiteConfigurationsOnPackageInitialization.php
index 73854190c009416af262e84890c2eed53d491b2a..50142bbcec2710c462872d78375d41e04d20c11b 100644
--- a/typo3/sysext/impexp/Classes/Initialization/ImportSiteConfigurationsOnPackageInitialization.php
+++ b/typo3/sysext/impexp/Classes/Initialization/ImportSiteConfigurationsOnPackageInitialization.php
@@ -23,6 +23,7 @@ use Symfony\Component\Finder\Finder;
 use TYPO3\CMS\Core\Attribute\AsEventListener;
 use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Package\Event\PackageInitializationEvent;
 use TYPO3\CMS\Core\Registry;
@@ -39,6 +40,7 @@ final class ImportSiteConfigurationsOnPackageInitialization implements LoggerAwa
     public function __construct(
         private readonly Registry $registry,
         private readonly SiteConfiguration $siteConfiguration,
+        private readonly SiteWriter $siteWriter,
     ) {}
 
     #[AsEventListener(after: ImportContentOnPackageInitialization::class)]
@@ -98,7 +100,7 @@ final class ImportSiteConfigurationsOnPackageInitialization implements LoggerAwa
             $configuration = $this->siteConfiguration->load($siteIdentifier);
             $configuration['rootPageId'] = $importedPageId;
             try {
-                $this->siteConfiguration->write($siteIdentifier, $configuration);
+                $this->siteWriter->write($siteIdentifier, $configuration);
             } catch (SiteConfigurationWriteException $e) {
                 $this->logger->warning(
                     sprintf(
diff --git a/typo3/sysext/install/Classes/Service/SetupService.php b/typo3/sysext/install/Classes/Service/SetupService.php
index 72d64aacf70bc0e94a099d88840411574258036e..40577f466d4670300859bc34923112f805b1219d 100644
--- a/typo3/sysext/install/Classes/Service/SetupService.php
+++ b/typo3/sysext/install/Classes/Service/SetupService.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Install\Service;
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
 use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
 use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash;
@@ -42,7 +42,7 @@ readonly class SetupService
 {
     public function __construct(
         private ConfigurationManager $configurationManager,
-        private SiteConfiguration $siteConfiguration,
+        private SiteWriter $siteWriter,
         private YamlFileLoader $yamlFileLoader,
     ) {}
 
@@ -58,7 +58,7 @@ readonly class SetupService
     public function createSiteConfiguration(string $identifier, int $rootPageId, string $siteUrl): void
     {
         // Create a default site configuration called "main" as best practice
-        $this->siteConfiguration->createNewBasicSite($identifier, $rootPageId, $siteUrl);
+        $this->siteWriter->createNewBasicSite($identifier, $rootPageId, $siteUrl);
     }
 
     /**
diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php
index 13e7f2783f1aad2757e64f532d7ef665dd15c16c..45acdc612da63c344b94d078e8efa28c059642ab 100644
--- a/typo3/sysext/install/Classes/ServiceProvider.php
+++ b/typo3/sysext/install/Classes/ServiceProvider.php
@@ -21,7 +21,7 @@ use Psr\Container\ContainerInterface;
 use Psr\EventDispatcher\EventDispatcherInterface;
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
 use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Console\CommandRegistry;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\Crypto\HashService;
@@ -236,7 +236,7 @@ class ServiceProvider extends AbstractServiceProvider
     {
         return new Service\SetupService(
             $container->get(ConfigurationManager::class),
-            $container->get(SiteConfiguration::class),
+            $container->get(SiteWriter::class),
             $container->get(YamlFileLoader::class)
         );
     }
diff --git a/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php b/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php
index 861386c787e8b7ad0299f7933395cfe29c93907f..f0162e605b66f8b4f329cc05deb241db6e9e0a3c 100644
--- a/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php
+++ b/typo3/sysext/install/Classes/Updates/MigrateSiteSettingsConfigUpdate.php
@@ -19,6 +19,7 @@ namespace TYPO3\CMS\Install\Updates;
 
 use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException;
 use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Attribute\UpgradeWizard;
 
@@ -34,11 +35,13 @@ class MigrateSiteSettingsConfigUpdate implements UpgradeWizardInterface
     protected const SETTINGS_FILENAME = 'settings.yaml';
 
     protected ?SiteConfiguration $siteConfiguration = null;
+    protected ?SiteWriter $siteWriter = null;
     protected array $sitePathsToMigrate = [];
 
     public function __construct()
     {
         $this->siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
+        $this->siteWriter = GeneralUtility::makeInstance(SiteWriter::class);
         $this->sitePathsToMigrate = $this->getSitePathsToMigrate();
     }
 
@@ -58,7 +61,7 @@ class MigrateSiteSettingsConfigUpdate implements UpgradeWizardInterface
     {
         try {
             foreach ($this->sitePathsToMigrate as $siteIdentifier => $settings) {
-                $this->siteConfiguration->writeSettings($siteIdentifier, $settings);
+                $this->siteWriter->writeSettings($siteIdentifier, $settings);
             }
         } catch (SiteConfigurationWriteException $e) {
             return false;
diff --git a/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php b/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php
index 76e4ddba4b2828460c117870002b575581391878..96fb9cec1cbf55120603b688b4a4481a4c81ff23 100644
--- a/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php
+++ b/typo3/sysext/install/Tests/Functional/Updates/MigrateSiteSettingsConfigUpdateTest.php
@@ -18,9 +18,8 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Install\Tests\Functional\Updates;
 
 use PHPUnit\Framework\Attributes\Test;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Core\Environment;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Updates\MigrateSiteSettingsConfigUpdate;
 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
@@ -31,7 +30,7 @@ final class MigrateSiteSettingsConfigUpdateTest extends FunctionalTestCase
     {
         $siteconfigurationIdentifier = 'settings';
 
-        GeneralUtility::makeInstance(SiteConfiguration::class)->write(
+        $this->get(SiteWriter::class)->write(
             $siteconfigurationIdentifier,
             [
                 'rootPageId' => 1,
@@ -66,7 +65,7 @@ final class MigrateSiteSettingsConfigUpdateTest extends FunctionalTestCase
     {
         $siteconfigurationIdentifier = 'withoutSettings';
 
-        GeneralUtility::makeInstance(SiteConfiguration::class)->write(
+        $this->get(SiteWriter::class)->write(
             $siteconfigurationIdentifier,
             [
                 'rootPageId' => 2,
diff --git a/typo3/sysext/redirects/Tests/Functional/EventListener/AddPageTypeZeroSourceTest.php b/typo3/sysext/redirects/Tests/Functional/EventListener/AddPageTypeZeroSourceTest.php
index c6add9614f44ca24acf16ea271922c4c6de7ec51..80092641180e3571a6c6fd797092804c91acfbf4 100644
--- a/typo3/sysext/redirects/Tests/Functional/EventListener/AddPageTypeZeroSourceTest.php
+++ b/typo3/sysext/redirects/Tests/Functional/EventListener/AddPageTypeZeroSourceTest.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Redirects\Tests\Functional\EventListener;
 use PHPUnit\Framework\Attributes\Test;
 use Psr\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\DependencyInjection\Container;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\EventDispatcher\ListenerProvider;
 use TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException;
@@ -250,7 +250,7 @@ final class AddPageTypeZeroSourceTest extends FunctionalTestCase
 
     protected function buildSite(array $configuration): void
     {
-        $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 }
diff --git a/typo3/sysext/redirects/Tests/Functional/EventListener/AddPlainSlugReplacementSourceTest.php b/typo3/sysext/redirects/Tests/Functional/EventListener/AddPlainSlugReplacementSourceTest.php
index 090b4ae1b18ab56a3a58459ca241c11d53809f33..a56bcffc591de81fa82db575f5c22c41adb2911b 100644
--- a/typo3/sysext/redirects/Tests/Functional/EventListener/AddPlainSlugReplacementSourceTest.php
+++ b/typo3/sysext/redirects/Tests/Functional/EventListener/AddPlainSlugReplacementSourceTest.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Redirects\Tests\Functional\EventListener;
 use PHPUnit\Framework\Attributes\Test;
 use Psr\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\DependencyInjection\Container;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
@@ -80,7 +80,7 @@ final class AddPlainSlugReplacementSourceTest extends FunctionalTestCase
             'base' => '/',
             'settings' => $settings,
         ];
-        $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 }
diff --git a/typo3/sysext/redirects/Tests/Functional/RedirectUpdate/SlugRedirectChangeItemFactoryTest.php b/typo3/sysext/redirects/Tests/Functional/RedirectUpdate/SlugRedirectChangeItemFactoryTest.php
index e66183d1e3dce5009b254b3cbbe1bfddc4607c58..084d5674a4b6419fcd953e241332c8d939b4adfc 100644
--- a/typo3/sysext/redirects/Tests/Functional/RedirectUpdate/SlugRedirectChangeItemFactoryTest.php
+++ b/typo3/sysext/redirects/Tests/Functional/RedirectUpdate/SlugRedirectChangeItemFactoryTest.php
@@ -19,9 +19,8 @@ namespace TYPO3\CMS\Redirects\Tests\Functional\RedirectUpdate;
 
 use PHPUnit\Framework\Attributes\Test;
 use Symfony\Component\DependencyInjection\Container;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\EventDispatcher\ListenerProvider;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
 use TYPO3\CMS\Redirects\RedirectUpdate\SlugRedirectChangeItem;
 use TYPO3\CMS\Redirects\RedirectUpdate\SlugRedirectChangeItemFactory;
@@ -138,7 +137,7 @@ final class SlugRedirectChangeItemFactoryTest extends FunctionalTestCase
             'base' => '/',
             'settings' => $settings,
         ];
-        $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 }
diff --git a/typo3/sysext/redirects/Tests/Functional/Service/SlugServiceTest.php b/typo3/sysext/redirects/Tests/Functional/Service/SlugServiceTest.php
index 160cfb46c0a38cc5de663a05521cdca8291341da..38b8947cc511fd15f9a1e1c9f4b0d65e2e1bf6f1 100644
--- a/typo3/sysext/redirects/Tests/Functional/Service/SlugServiceTest.php
+++ b/typo3/sysext/redirects/Tests/Functional/Service/SlugServiceTest.php
@@ -21,7 +21,7 @@ use PHPUnit\Framework\Attributes\Test;
 use Psr\EventDispatcher\EventDispatcherInterface;
 use Psr\Log\NullLogger;
 use Symfony\Component\DependencyInjection\Container;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Context\Context;
 use TYPO3\CMS\Core\DataHandling\Model\CorrelationId;
 use TYPO3\CMS\Core\Domain\Repository\PageRepository;
@@ -563,8 +563,8 @@ final class SlugServiceTest extends FunctionalTestCase
             'rootPageId' => 1,
             'base' => '/',
         ];
-        $siteConfiguration = $this->get(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 
     protected function buildBaseSiteInSubfolder(): void
@@ -573,8 +573,8 @@ final class SlugServiceTest extends FunctionalTestCase
             'rootPageId' => 1,
             'base' => '/sub-folder',
         ];
-        $siteConfiguration = $this->get(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 
     protected function buildBaseSiteWithLanguages(): void
@@ -584,8 +584,8 @@ final class SlugServiceTest extends FunctionalTestCase
             'base' => '/',
             'languages' => $this->languages,
         ];
-        $siteConfiguration = $this->get(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 
     protected function buildBaseSiteWithLanguagesInSubFolder(): void
@@ -603,8 +603,8 @@ final class SlugServiceTest extends FunctionalTestCase
             'base' => '/sub-folder',
             'languages' => $languages,
         ];
-        $siteConfiguration = $this->get(SiteConfiguration::class);
-        $siteConfiguration->write('testing', $configuration);
+        $siteWriter = $this->get(SiteWriter::class);
+        $siteWriter->write('testing', $configuration);
     }
 
     protected function createSubject(): void
diff --git a/typo3/sysext/styleguide/Classes/TcaDataGenerator/AbstractGenerator.php b/typo3/sysext/styleguide/Classes/TcaDataGenerator/AbstractGenerator.php
index d31fce1ead7decbebd79a455f770be65a0b2efca..d4f118a87c74250c0ff8a49b32cc7e17cacbbc65 100644
--- a/typo3/sysext/styleguide/Classes/TcaDataGenerator/AbstractGenerator.php
+++ b/typo3/sysext/styleguide/Classes/TcaDataGenerator/AbstractGenerator.php
@@ -18,7 +18,7 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Styleguide\TcaDataGenerator;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -46,9 +46,9 @@ abstract class AbstractGenerator
         $recordFinder = GeneralUtility::makeInstance(RecordFinder::class);
         // When the DataHandler created the page tree, a default site configuration has been added. Fetch,  rename, update.
         $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByRootPageId($topPageUid);
-        $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
+        $siteWriter = GeneralUtility::makeInstance(SiteWriter::class);
         $siteIdentifier = 'styleguide-demo-' . $topPageUid;
-        $siteConfiguration->rename($site->getIdentifier(), $siteIdentifier);
+        $siteWriter->rename($site->getIdentifier(), $siteIdentifier);
         $highestLanguageId = $recordFinder->findHighestLanguageId();
         $configuration = [
             'base' => $base . 'styleguide-demo-' . $topPageUid,
@@ -138,7 +138,7 @@ abstract class AbstractGenerator
                 ],
             ],
         ];
-        $siteConfiguration->write($siteIdentifier, $configuration);
+        $siteWriter->write($siteIdentifier, $configuration);
     }
 
     /**
diff --git a/typo3/sysext/styleguide/Classes/TcaDataGenerator/Generator.php b/typo3/sysext/styleguide/Classes/TcaDataGenerator/Generator.php
index fb9c514bff25b36694bfc7df465109f01b7b8acb..e7c7cb46efebd3ea58d323e78dda6b6724074b02 100644
--- a/typo3/sysext/styleguide/Classes/TcaDataGenerator/Generator.php
+++ b/typo3/sysext/styleguide/Classes/TcaDataGenerator/Generator.php
@@ -17,7 +17,7 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Styleguide\TcaDataGenerator;
 
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory;
 use TYPO3\CMS\Core\Crypto\Random;
 use TYPO3\CMS\Core\Database\ConnectionPool;
@@ -200,7 +200,7 @@ final class Generator extends AbstractGenerator
         // Delete site configuration
         if ($topUids[0] ?? false) {
             $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByRootPageId($topUids[0]);
-            GeneralUtility::makeInstance(SiteConfiguration::class)->delete($site->getIdentifier());
+            GeneralUtility::makeInstance(SiteWriter::class)->delete($site->getIdentifier());
         }
     }
 
diff --git a/typo3/sysext/styleguide/Classes/TcaDataGenerator/GeneratorFrontend.php b/typo3/sysext/styleguide/Classes/TcaDataGenerator/GeneratorFrontend.php
index 38fd0947114b0101890495bbdb358c12b50fd523..b6196d4d8bf6eefce9d3336a0fc184ae7e953825 100644
--- a/typo3/sysext/styleguide/Classes/TcaDataGenerator/GeneratorFrontend.php
+++ b/typo3/sysext/styleguide/Classes/TcaDataGenerator/GeneratorFrontend.php
@@ -17,7 +17,7 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Styleguide\TcaDataGenerator;
 
-use TYPO3\CMS\Core\Configuration\SiteConfiguration;
+use TYPO3\CMS\Core\Configuration\SiteWriter;
 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\Site\SiteFinder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -204,7 +204,7 @@ final class GeneratorFrontend extends AbstractGenerator
             if (!empty($rootUid)) {
                 $site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByRootPageId((int)$rootUid[0]);
                 $identifier = $site->getIdentifier();
-                GeneralUtility::makeInstance(SiteConfiguration::class)->delete($identifier);
+                GeneralUtility::makeInstance(SiteWriter::class)->delete($identifier);
             }
         } catch (SiteNotFoundException $e) {
             // Do not throw a thing if site config does not exist