diff --git a/core/includes/file.inc b/core/includes/file.inc index effb71c..d47fbc4 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -1520,9 +1520,10 @@ function drupal_tempnam($directory, $prefix) { * A string containing the path to the temporary directory. */ function file_directory_temp() { - $config = \Drupal::config('system.file'); - $temporary_directory = $config->get('path.temporary'); + $temporary_directory = \Drupal::config('system.file')->get('path.temporary'); if (empty($temporary_directory)) { + // Needs set up. + $config = \Drupal::configFactory()->getEditable('system.file'); $temporary_directory = file_directory_os_temp(); if (empty($temporary_directory)) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 1ec434d..d3d7a04 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1647,7 +1647,7 @@ function install_download_additional_translations_operations(&$install_state) { // If a non-English language was selected, change the default language and // remove English. if ($langcode != 'en') { - \Drupal::config('system.site')->set('langcode', $langcode)->save(); + \Drupal::configFactory()->getEditable('system.site')->set('langcode', $langcode)->save(); \Drupal::service('language.default')->set($language); if (empty($install_state['profile_info']['keep_english'])) { entity_delete_multiple('configurable_language', array('en')); diff --git a/core/includes/install.inc b/core/includes/install.inc index ad911db..e247378 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -618,7 +618,7 @@ function drupal_install_system($install_state) { // Ensure default language is saved. if (isset($install_state['parameters']['langcode'])) { - \Drupal::config('system.site') + \Drupal::configFactory()->getEditable('system.site') ->set('langcode', $install_state['parameters']['langcode']) ->save(); } diff --git a/core/includes/module.inc b/core/includes/module.inc index ff11244..824cd31 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -211,8 +211,7 @@ function drupal_required_modules() { * An integer representing the weight of the module. */ function module_set_weight($module, $weight) { - // Update the module weight in the config file that contains it. - $extension_config = \Drupal::config('core.extension'); + $extension_config = \Drupal::configFactory()->getEditable('core.extension'); if ($extension_config->get("module.$module") !== NULL) { $extension_config ->set("module.$module", $weight) diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index 141686f..f52a3b7 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -298,8 +298,8 @@ public static function lock() { * a configuration file. For @code \Drupal::config('book.admin') @endcode, the config * object returned will contain the contents of book.admin configuration file. * - * @return \Drupal\Core\Config\Config - * A configuration object. + * @return \Drupal\Core\Config\ImmutableConfig + * An immutable configuration object. */ public static function config($name) { return static::$container->get('config.factory')->get($name); diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index d354799..2d8e303 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -78,8 +78,7 @@ public function __construct($name, StorageInterface $storage, EventDispatcherInt */ public function initWithData(array $data) { parent::initWithData($data); - $this->settingsOverrides = array(); - $this->moduleOverrides = array(); + $this->resetOverriddenData(); return $this; } diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index b1a8932..2cde0d4 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -104,15 +104,41 @@ public function getOverrideState() { /** * {@inheritdoc} */ + public function getEditable($name, $override_free = TRUE) { + $old_state = $this->getOverrideState(); + $this->setOverrideState(FALSE); + $config = $this->doGet($name, FALSE); + $this->setOverrideState($old_state); + return $config; + } + + /** + * {@inheritdoc} + */ public function get($name) { - if ($config = $this->loadMultiple(array($name))) { + return $this->doGet($name); + } + + /** + * Returns a configuration object for a given name. + * + * @param string $name + * The name of the configuration object to construct. + * @param bool $immutable + * (optional) Create an immutable configuration object. Defaults to TRUE. + * + * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig + * A configuration object. + */ + protected function doGet($name, $immutable = TRUE) { + if ($config = $this->loadMultiple(array($name), $immutable)) { return $config[$name]; } else { // If the configuration object does not exist in the configuration // storage, create a new object and add it to the static cache. - $cache_key = $this->getConfigCacheKey($name); - $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); + $cache_key = $this->getConfigCacheKey($name, $immutable); + $this->cache[$cache_key] = $this->createConfigObject($name, $immutable); if ($this->useOverrides) { // Get and apply any overrides. @@ -132,11 +158,11 @@ public function get($name) { /** * {@inheritdoc} */ - public function loadMultiple(array $names) { + public function loadMultiple(array $names, $immutable = TRUE) { $list = array(); foreach ($names as $key => $name) { - $cache_key = $this->getConfigCacheKey($name); + $cache_key = $this->getConfigCacheKey($name, $immutable); if (isset($this->cache[$cache_key])) { $list[$name] = $this->cache[$cache_key]; unset($names[$key]); @@ -155,9 +181,9 @@ public function loadMultiple(array $names) { } foreach ($storage_data as $name => $data) { - $cache_key = $this->getConfigCacheKey($name); + $cache_key = $this->getConfigCacheKey($name, $immutable); - $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); + $this->cache[$cache_key] = $this->createConfigObject($name, $immutable); $this->cache[$cache_key]->initWithData($data); if ($this->useOverrides) { if (isset($module_overrides[$name])) { @@ -228,7 +254,7 @@ public function rename($old_name, $new_name) { // Prime the cache and load the configuration with the correct overrides. $config = $this->get($new_name); $this->eventDispatcher->dispatch(ConfigEvents::RENAME, new ConfigRenameEvent($config, $old_name)); - return $config; + return $this; } /** @@ -252,12 +278,14 @@ public function getCacheKeys() { * * @param string $name * The name of the configuration object. + * @param bool $immutable + * Whether or not the object is mutable. * * @return string * The cache key. */ - protected function getConfigCacheKey($name) { - return $name . ':' . implode(':', $this->getCacheKeys()); + protected function getConfigCacheKey($name, $immutable) { + return $name . ':' . implode(':', $this->getCacheKeys()) . ':' . ($immutable ? static::IMMUTABLE: static::MUTABLE); } /** @@ -292,7 +320,7 @@ public function listAll($prefix = '') { } /** - * Removes stale static cache entries when configuration is saved. + * Updates stale static cache entries when configuration is saved. * * @param ConfigCrudEvent $event * The configuration event. @@ -305,7 +333,9 @@ public function onConfigSave(ConfigCrudEvent $event) { foreach ($this->getConfigCacheKeys($saved_config->getName()) as $cache_key) { $cached_config = $this->cache[$cache_key]; if ($cached_config !== $saved_config) { - $this->cache[$cache_key]->setData($saved_config->getRawData()); + // We can not just update the data since other things about the object + // might have changed. For example, whether or not it is new. + $this->cache[$cache_key]->initWithData($saved_config->getRawData()); } } } @@ -339,4 +369,22 @@ public function addOverride(ConfigFactoryOverrideInterface $config_factory_overr $this->configFactoryOverrides[] = $config_factory_override; } + /** + * Creates a configuration object. + * + * @param string $name + * Configuration object name. + * @param bool $immutable + * Determines whether a mutable or immutable config object is returned. + * + * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig + * The configuration object. + */ + protected function createConfigObject($name, $immutable) { + if ($immutable) { + return new ImmutableConfig($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); + } + return new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); + } + } diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php index d51e023..c58521e 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php +++ b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php @@ -15,6 +15,16 @@ interface ConfigFactoryInterface { /** + * Constant used in static cache keys for mutable config objects. + */ + const MUTABLE = 'mutable'; + + /** + * Constant used in static cache keys for immutable config objects. + */ + const IMMUTABLE = 'immutable'; + + /** * Sets the override state. * * @param bool $state @@ -33,17 +43,31 @@ public function setOverrideState($state); public function getOverrideState(); /** - * Returns a configuration object for a given name. + * Returns an immutable configuration object for a given name. * * @param string $name * The name of the configuration object to construct. * - * @return \Drupal\Core\Config\Config + * @return \Drupal\Core\Config\ImmutableConfig * A configuration object. */ public function get($name); /** + * Returns an mutable configuration object for a given name. + * + * Should not be used for config that will have runtime effects. Therefore it + * is always loaded override free. + * + * @param string $name + * The name of the configuration object to construct. + * + * @return \Drupal\Core\Config\Config + * A configuration object. + */ + public function getEditable($name); + + /** * Returns a list of configuration objects for the given names. * * This will pre-load all requested configuration objects does not create @@ -51,11 +75,13 @@ public function get($name); * * @param array $names * List of names of configuration objects. + * @param bool $immutable + * (optional) Create an immutable configuration object. Defaults to TRUE. * - * @return \Drupal\Core\Config\Config[] + * @return \Drupal\Core\Config\Config[]|\Drupal\Core\Config\ImmutableConfig[] * List of successfully loaded configuration objects, keyed by name. */ - public function loadMultiple(array $names); + public function loadMultiple(array $names, $immutable = TRUE); /** * Resets and re-initializes configuration objects. Internal use only. @@ -76,8 +102,7 @@ public function reset($name = NULL); * @param string $new_name * The new name of the configuration object. * - * @return \Drupal\Core\Config\Config - * The renamed config object. + * @return $this */ public function rename($old_name, $new_name); diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php index a97cf72..da0fa98 100644 --- a/core/lib/Drupal/Core/Config/ConfigManager.php +++ b/core/lib/Drupal/Core/Config/ConfigManager.php @@ -224,7 +224,7 @@ public function uninstall($type, $name) { $config_names = $this->configFactory->listAll($name . '.'); foreach ($config_names as $config_name) { - $this->configFactory->get($config_name)->delete(); + $this->configFactory->getEditable($config_name)->delete(); } // Remove any matching configuration from collections. diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index ca6ed7a..a686839 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -200,8 +200,7 @@ protected function doCreate(array $values) { */ protected function doDelete($entities) { foreach ($entities as $entity) { - $config = $this->configFactory->get($this->getPrefix() . $entity->id()); - $config->delete(); + $this->configFactory->getEditable($this->getPrefix() . $entity->id())->delete(); } } @@ -238,16 +237,15 @@ public function save(EntityInterface $entity) { protected function doSave($id, EntityInterface $entity) { $is_new = $entity->isNew(); $prefix = $this->getPrefix(); + $config_name = $prefix . $entity->id(); if ($id !== $entity->id()) { // Renaming a config object needs to cater for: // - Storage needs to access the original object. // - The object needs to be renamed/copied in ConfigFactory and reloaded. // - All instances of the object need to be renamed. - $config = $this->configFactory->rename($prefix . $id, $prefix . $entity->id()); - } - else { - $config = $this->configFactory->get($prefix . $id); + $this->configFactory->rename($prefix . $id, $config_name); } + $config = $this->configFactory->getEditable($config_name); // Retrieve the desired properties and set them in config. $config->setData($this->mapToStorageRecord($entity)); diff --git a/core/lib/Drupal/Core/Config/ImmutableConfig.php b/core/lib/Drupal/Core/Config/ImmutableConfig.php new file mode 100644 index 0000000..61e7fdd --- /dev/null +++ b/core/lib/Drupal/Core/Config/ImmutableConfig.php @@ -0,0 +1,61 @@ + $this->getName(), '!key' => $key])); + } + + /** + * {@inheritdoc} + */ + public function clear($key) { + throw new ImmutableConfigException(String::format('Can not clear !key key in immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName(), '!key' => $key])); + } + + /** + * {@inheritdoc} + */ + public function save() { + throw new ImmutableConfigException(String::format('Can not save immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()])); + } + + /** + * Deletes the configuration object. + * + * @return \Drupal\Core\Config\Config + * The configuration object. + */ + public function delete() { + throw new ImmutableConfigException(String::format('Can not delete immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()])); + } + +} diff --git a/core/lib/Drupal/Core/Config/ImmutableConfigException.php b/core/lib/Drupal/Core/Config/ImmutableConfigException.php new file mode 100644 index 0000000..4df074a --- /dev/null +++ b/core/lib/Drupal/Core/Config/ImmutableConfigException.php @@ -0,0 +1,16 @@ +getEditable('core.extension'); if ($enable_dependencies) { // Get all module data so we can find dependencies and sort. $module_data = system_rebuild_module_data(); @@ -300,8 +300,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { return FALSE; } - // Only process currently installed modules. - $extension_config = \Drupal::config('core.extension'); + $extension_config = \Drupal::configFactory()->getEditable('core.extension'); $installed_modules = $extension_config->get('module') ?: array(); if (!$module_list = array_intersect_key($module_list, $installed_modules)) { // Nothing to do. All modules already uninstalled. @@ -387,8 +386,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { drupal_uninstall_schema($module); // Remove the module's entry from the config. - $extension_config = \Drupal::config('core.extension'); - $extension_config->clear("module.$module")->save(); + \Drupal::configFactory()->getEditable('core.extension')->clear("module.$module")->save(); // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 89ad503..2f0fd94 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -179,7 +179,7 @@ public function setDefault($name) { if (!isset($list[$name])) { throw new \InvalidArgumentException("$name theme is not installed."); } - $this->configFactory->get('system.theme') + $this->configFactory->getEditable('system.theme') ->set('default', $name) ->save(); return $this; @@ -189,7 +189,7 @@ public function setDefault($name) { * {@inheritdoc} */ public function install(array $theme_list, $install_dependencies = TRUE) { - $extension_config = $this->configFactory->get('core.extension'); + $extension_config = $this->configFactory->getEditable('core.extension'); $theme_data = $this->rebuildThemeData(); @@ -313,8 +313,8 @@ public function install(array $theme_list, $install_dependencies = TRUE) { * {@inheritdoc} */ public function uninstall(array $theme_list) { - $extension_config = $this->configFactory->get('core.extension'); - $theme_config = $this->configFactory->get('system.theme'); + $extension_config = $this->configFactory->getEditable('core.extension'); + $theme_config = $this->configFactory->getEditable('system.theme'); $list = $this->listInfo(); foreach ($theme_list as $key) { if (!isset($list[$key])) { diff --git a/core/lib/Drupal/Core/Form/ConfigFormBase.php b/core/lib/Drupal/Core/Form/ConfigFormBase.php index f58bc11..5ed650a 100644 --- a/core/lib/Drupal/Core/Form/ConfigFormBase.php +++ b/core/lib/Drupal/Core/Form/ConfigFormBase.php @@ -15,6 +15,7 @@ * Base class for implementing system configuration forms. */ abstract class ConfigFormBase extends FormBase { + use ConfigFormBaseTrait; /** * Constructs a \Drupal\system\ConfigFormBase object. @@ -59,20 +60,4 @@ public function submitForm(array &$form, FormStateInterface $form_state) { drupal_set_message($this->t('The configuration options have been saved.')); } - /** - * {@inheritdoc} - * - * Overrides \Drupal\Core\Form\FormBase::config() so that configuration is - * returned override free. This ensures that overrides do not pollute saved - * configuration. - */ - protected function config($name) { - $config_factory = $this->configFactory(); - $old_state = $config_factory->getOverrideState(); - $config_factory->setOverrideState(FALSE); - $config = $config_factory->get($name); - $config_factory->setOverrideState($old_state); - return $config; - } - } diff --git a/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php new file mode 100644 index 0000000..11249f8 --- /dev/null +++ b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php @@ -0,0 +1,77 @@ +configFactory(); + } + elseif (property_exists($this, 'configFactory')) { + $config_factory = $this->configFactory; + } + if (!isset($config_factory) || !($config_factory instanceof ConfigFactoryInterface)) { + throw new \LogicException('No config factory available for ConfigFormBaseTrait'); + } + if (in_array($name, $this->getEditableConfigNames())) { + // Get a mutable object from the factory. + $config = $config_factory->getEditable($name); + } + else { + $config = $config_factory->get($name); + } + return $config; + } + + /** + * Gets the configuration names that will be editable. + * + * @return array + * An array of configuration object names that are editable if called in + * conjunction with the trait's config() method. + */ + abstract protected function getEditableConfigNames(); + +} diff --git a/core/lib/Drupal/Core/Form/FormBase.php b/core/lib/Drupal/Core/Form/FormBase.php index 3a14612..d516cfa 100644 --- a/core/lib/Drupal/Core/Form/FormBase.php +++ b/core/lib/Drupal/Core/Form/FormBase.php @@ -80,7 +80,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) { * the config object returned will contain the contents of book.admin * configuration file. * - * @return \Drupal\Core\Config\Config + * @return \Drupal\Core\Config\ImmutableConfig * A configuration object. */ protected function config($name) { diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php index ba55764..0354e25 100644 --- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php @@ -100,6 +100,17 @@ public function getFormId() { /** * {@inheritdoc} */ + protected function getEditableConfigNames() { + return [ + 'system.date', + 'system.site', + 'update.settings', + ]; + } + + /** + * {@inheritdoc} + */ public function buildForm(array $form, FormStateInterface $form_state) { $form['#title'] = $this->t('Configure site'); diff --git a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php index 86d8f85..c070e12 100644 --- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php +++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php @@ -17,6 +17,10 @@ class StaticMenuLinkOverrides implements StaticMenuLinkOverridesInterface { /** * The config name used to store the overrides. * + * This configuration can not be overridden by configuration overrides because + * menu links and these overrides are cached in a way that is not override + * aware. + * * @var string */ protected $configName = 'core.menu.static_menu_link_overrides'; @@ -54,7 +58,8 @@ public function __construct(ConfigFactoryInterface $config_factory) { */ protected function getConfig() { if (empty($this->config)) { - $this->config = $this->configFactory->get($this->configName); + // Get an override free and editable configuration object. + $this->config = $this->configFactory->getEditable($this->configName); } return $this->config; } @@ -135,7 +140,7 @@ public function saveOverride($id, array $definition) { $definition = array_intersect_key($definition, $expected); if ($definition) { $id = static::encodeId($id); - $all_overrides = $this->getConfig()->get('definitions'); + $all_overrides = $this->getConfig()->get('definitions', FALSE); // Combine with any existing data. $all_overrides[$id] = $definition + $this->loadOverride($id); $this->getConfig()->set('definitions', $all_overrides)->save(); diff --git a/core/modules/aggregator/src/Form/SettingsForm.php b/core/modules/aggregator/src/Form/SettingsForm.php index ff6fd62..69c5ed6 100644 --- a/core/modules/aggregator/src/Form/SettingsForm.php +++ b/core/modules/aggregator/src/Form/SettingsForm.php @@ -99,6 +99,13 @@ public function getFormId() { /** * {@inheritdoc} */ + protected function getEditableConfigNames() { + return ['aggregator.settings']; + } + + /** + * {@inheritdoc} + */ public function buildForm(array $form, FormStateInterface $form_state) { $config = $this->config('aggregator.settings'); diff --git a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php index f6c1412..f51a403 100644 --- a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php +++ b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php @@ -16,6 +16,7 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\Query\QueryInterface; +use Drupal\Core\Form\ConfigFormBaseTrait; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Routing\UrlGeneratorTrait; @@ -33,7 +34,7 @@ * ) */ class DefaultProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface { - + use ConfigFormBaseTrait; use UrlGeneratorTrait; /** @@ -110,8 +111,16 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} */ + protected function getEditableConfigNames() { + return ['aggregator.settings']; + } + + /** + * {@inheritdoc} + */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { - $processors = $this->configuration['processors']; + $config = $this->config('aggregator.settings'); + $processors = $config->get('processors'); $info = $this->getPluginDefinition(); $counts = array(3, 5, 10, 15, 20, 25); $items = array_map(function ($count) { @@ -135,7 +144,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta $form['processors'][$info['id']]['aggregator_summary_items'] = array( '#type' => 'select', '#title' => t('Number of items shown in listing pages'), - '#default_value' => $this->configuration['source']['list_max'], + '#default_value' => $config->get('source.list_max'), '#empty_value' => 0, '#options' => $items, ); @@ -143,7 +152,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta $form['processors'][$info['id']]['aggregator_clear'] = array( '#type' => 'select', '#title' => t('Discard items older than'), - '#default_value' => $this->configuration['items']['expire'], + '#default_value' => $config->get('items.expire'), '#options' => $period, '#description' => t('Requires a correctly configured cron maintenance task.', array('@cron' => $this->url('system.status'))), ); @@ -156,7 +165,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta $form['processors'][$info['id']]['aggregator_teaser_length'] = array( '#type' => 'select', '#title' => t('Length of trimmed description'), - '#default_value' => $this->configuration['items']['teaser_length'], + '#default_value' => $config->get('items.teaser_length'), '#options' => $options, '#description' => t('The maximum number of characters used in the trimmed version of content.'), ); @@ -275,7 +284,7 @@ public function getConfiguration() { * {@inheritdoc} */ public function setConfiguration(array $configuration) { - $config = $this->configFactory->get('aggregator.settings'); + $config = $this->config('aggregator.settings'); foreach ($configuration as $key => $value) { $config->set($key, $value); } diff --git a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php index c930701..1a6ee19 100644 --- a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php +++ b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php @@ -11,6 +11,7 @@ use Drupal\aggregator\Plugin\ProcessorInterface; use Drupal\aggregator\FeedInterface; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Form\ConfigFormBaseTrait; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -27,6 +28,7 @@ * ) */ class TestProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface { + use ConfigFormBaseTrait; /** * Contains the configuration object factory. @@ -67,8 +69,15 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition /** * {@inheritdoc} */ + protected function getEditableConfigNames() { + return ['aggregator_test.settings']; + } + + /** + * {@inheritdoc} + */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { - $processors = $this->configFactory->get('aggregator.settings')->get('processors'); + $processors = $this->config('aggregator.settings')->get('processors'); $info = $this->getPluginDefinition(); $form['processors'][$info['id']] = array( @@ -134,7 +143,7 @@ public function getConfiguration() { * {@inheritdoc} */ public function setConfiguration(array $configuration) { - $config = $this->configFactory->get('aggregator_test.settings'); + $config = $this->config('aggregator_test.settings'); foreach ($configuration as $key => $value) { $config->set($key, $value); } diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 51da823..57ee1ab 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -559,7 +559,7 @@ function book_type_is_allowed($type) { */ function book_node_type_update(NodeTypeInterface $type) { if ($type->getOriginalId() != $type->id()) { - $config = \Drupal::config('book.settings'); + $config = \Drupal::configFactory()->getEditable('book.settings'); // Update the list of node types that are allowed to be added to books. $allowed_types = $config->get('allowed_types'); $old_key = array_search($type->getOriginalId(), $allowed_types); diff --git a/core/modules/book/src/Form/BookSettingsForm.php b/core/modules/book/src/Form/BookSettingsForm.php index fe1db37..0db0dc5 100644 --- a/core/modules/book/src/Form/BookSettingsForm.php +++ b/core/modules/book/src/Form/BookSettingsForm.php @@ -25,6 +25,13 @@ public function getFormId() { /** * {@inheritdoc} */ + protected function getEditableConfigNames() { + return ['book.settings']; + } + + /** + * {@inheritdoc} + */ public function buildForm(array $form, FormStateInterface $form_state) { $types = node_type_get_names(); $config = $this->config('book.settings'); diff --git a/core/modules/color/color.module b/core/modules/color/color.module index 5ad67f2..7d8473c 100644 --- a/core/modules/color/color.module +++ b/core/modules/color/color.module @@ -169,7 +169,9 @@ function color_get_palette($theme, $default = FALSE) { // Load variable. // @todo Default color config should be moved to yaml in the theme. - return \Drupal::config('color.theme.' . $theme)->get('palette') ?: $palette; + // Getting a mutable override-free object because overriding color + // configuration makes no sense. + return \Drupal::configFactory()->getEditable('color.theme.' . $theme)->get('palette') ?: $palette; } /** @@ -196,7 +198,12 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them // See if we're using a predefined scheme. // Note: we use the original theme when the default scheme is chosen. - $current_scheme = \Drupal::config('color.theme.' . $theme)->get('palette'); + // Note: we use configuration without overrides since this information is used + // in a form and therefore without doing this would bleed overrides into + // active configuration. + // Getting a mutable override-free object because overriding color + // configuration makes no sense. + $current_scheme = \Drupal::configFactory()->getEditable('color.theme.' . $theme)->get('palette'); foreach ($schemes as $key => $scheme) { if ($current_scheme == $scheme) { $scheme_name = $key; @@ -213,6 +220,7 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them } // Add scheme selector. + $default_palette = color_get_palette($theme, TRUE); $form['scheme'] = array( '#type' => 'select', '#title' => t('Color set'), @@ -226,7 +234,7 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them // Add custom JavaScript. 'drupalSettings' => [ 'color' => [ - 'reference' => color_get_palette($theme, TRUE), + 'reference' => $default_palette, 'schemes' => $schemes, ], 'gradients' => $info['gradients'], @@ -234,8 +242,8 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them ), ); - // Add palette fields. - $palette = color_get_palette($theme); + // Add palette fields. Use the configuration if available. + $palette = $current_scheme ?: $default_palette; $names = $info['fields']; $form['palette']['#tree'] = TRUE; foreach ($palette as $name => $value) { @@ -361,7 +369,7 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) { return; } - $config = \Drupal::config('color.theme.' . $theme); + $config = \Drupal::configFactory()->getEditable('color.theme.' . $theme); // Resolve palette. if ($scheme != '') { @@ -620,7 +628,7 @@ function _color_render_images($theme, &$info, &$paths, $palette) { if ($file == 'screenshot.png') { $slice = imagecreatetruecolor(150, 90); imagecopyresampled($slice, $target, 0, 0, $x, $y, 150, 90, $width, $height); - \Drupal::config('color.theme.' . $theme) + \Drupal::configFactory()->getEditable('color.theme.' . $theme) ->set('screenshot', $image) ->save(); } diff --git a/core/modules/config/src/Form/ConfigSingleImportForm.php b/core/modules/config/src/Form/ConfigSingleImportForm.php index 58156b0..ee1dfde 100644 --- a/core/modules/config/src/Form/ConfigSingleImportForm.php +++ b/core/modules/config/src/Form/ConfigSingleImportForm.php @@ -243,7 +243,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // If a simple configuration file was added, set the data and save. if ($this->data['config_type'] === 'system.simple') { - $this->config($this->data['config_name'])->setData($this->data['import'])->save(); + $this->configFactory()->getEditable($this->data['config_name'])->setData($this->data['import'])->save(); drupal_set_message($this->t('The %name configuration was imported.', array('%name' => $this->data['config_name']))); } // For a config entity, create an entity and save it. diff --git a/core/modules/config/src/Tests/ConfigCRUDTest.php b/core/modules/config/src/Tests/ConfigCRUDTest.php index 25391fe..f54caed 100644 --- a/core/modules/config/src/Tests/ConfigCRUDTest.php +++ b/core/modules/config/src/Tests/ConfigCRUDTest.php @@ -249,7 +249,7 @@ public function testDataTypes() { \Drupal::service('module_installer')->install(array('config_test')); $storage = new DatabaseStorage($this->container->get('database'), 'config'); $name = 'config_test.types'; - $config = $this->container->get('config.factory')->get($name); + $config = $this->config($name); $original_content = file_get_contents(drupal_get_path('module', 'config_test') . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY . "/$name.yml"); $this->verbose('
' . $original_content . "\n" . var_export($storage->read($name), TRUE));
 
@@ -299,7 +299,7 @@ public function testDataTypes() {
     // also fails.
     $typed_config_manager = $this->container->get('config.typed');
     $config_name = 'config_test.no_schema';
-    $config = $this->container->get('config.factory')->get($config_name);
+    $config = $this->config($config_name);
     $this->assertFalse($typed_config_manager->hasConfigSchema($config_name));
 
     try {
diff --git a/core/modules/config/src/Tests/ConfigEventsTest.php b/core/modules/config/src/Tests/ConfigEventsTest.php
index b4f7279..fb6eca6 100644
--- a/core/modules/config/src/Tests/ConfigEventsTest.php
+++ b/core/modules/config/src/Tests/ConfigEventsTest.php
@@ -67,11 +67,14 @@ function testConfigRenameEvent() {
     $GLOBALS['config'][$name] = array('key' => 'overridden');
     $GLOBALS['config'][$new_name] = array('key' => 'new overridden');
 
-    $config = \Drupal::config($name);
+    $config = $this->config($name);
     $config->set('key', 'initial')->save();
     $event = \Drupal::state()->get('config_events_test.event', array());
     $this->assertIdentical($event['event_name'], ConfigEvents::SAVE);
-    $this->assertIdentical($event['current_config_data'], array('key' => 'overridden'));
+    $this->assertIdentical($event['current_config_data'], array('key' => 'initial'));
+
+    // Override applies when getting runtime config.
+    $this->assertEqual($GLOBALS['config'][$name], \Drupal::config($name)->get());
 
     \Drupal::configFactory()->rename($name, $new_name);
     $event = \Drupal::state()->get('config_events_test.event', array());
diff --git a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
index 9de963c..cc754d4 100644
--- a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
+++ b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
@@ -76,7 +76,7 @@ function testConfigLanguageOverride() {
 
     // Test how overrides react to base configuration changes. Set up some base
     // values.
-    \Drupal::config('config_test.foo')
+    \Drupal::configFactory()->getEditable('config_test.foo')
       ->set('value', array('key' => 'original'))
       ->set('label', 'Original')
       ->save();
@@ -94,6 +94,7 @@ function testConfigLanguageOverride() {
     $this->assertIdentical($config->get('value'), array('key' => 'override'));
 
     // Ensure renaming the config will rename the override.
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('en'));
     \Drupal::configFactory()->rename('config_test.foo', 'config_test.bar');
     $config = \Drupal::config('config_test.bar');
     $this->assertEqual($config->get('value'), array('key' => 'original'));
@@ -108,7 +109,7 @@ function testConfigLanguageOverride() {
     $this->assertEqual($override->get('value'), array('key' => 'override'));
 
     // Ensure changing data in the config will update the overrides.
-    $config = \Drupal::config('config_test.bar')->clear('value.key')->save();
+    $config = \Drupal::configFactory()->getEditable('config_test.bar')->clear('value.key')->save();
     $this->assertEqual($config->get('value'), array());
     $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
     $this->assertFalse($override->isNew());
@@ -119,7 +120,7 @@ function testConfigLanguageOverride() {
     $this->assertEqual($override->get('value'), NULL);
 
     // Ensure deleting the config will delete the override.
-    \Drupal::configFactory()->get('config_test.bar')->delete();
+    \Drupal::configFactory()->getEditable('config_test.bar')->delete();
     $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
     $this->assertTrue($override->isNew());
     $this->assertEqual($override->get('value'), NULL);
diff --git a/core/modules/config/src/Tests/ConfigModuleOverridesTest.php b/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
index 41f144c..923b2f0 100644
--- a/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
+++ b/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
@@ -32,7 +32,7 @@ public function testSimpleModuleOverrides() {
     $non_overridden_slogan = 'Yay for defaults!';
     $config_factory = $this->container->get('config.factory');
     $config_factory
-      ->get($name)
+      ->getEditable($name)
       ->set('name', $non_overridden_name)
       ->set('slogan', $non_overridden_slogan)
       ->save();
diff --git a/core/modules/config/src/Tests/ConfigOverrideTest.php b/core/modules/config/src/Tests/ConfigOverrideTest.php
index 38ba0a1..7508896 100644
--- a/core/modules/config/src/Tests/ConfigOverrideTest.php
+++ b/core/modules/config/src/Tests/ConfigOverrideTest.php
@@ -55,14 +55,22 @@ function testConfOverride() {
     $this->assertFalse(isset($data['baz']));
     $this->assertIdentical($data['404'], $expected_original_data['404']);
 
-    // Get the configuration object in with overrides.
-    $config = \Drupal::config('config_test.system');
+    // Get the configuration object with overrides.
+    $config = \Drupal::configFactory()->get('config_test.system');
 
     // Verify that it contains the overridden data from $config.
     $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
     $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
     $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
 
+    // Get the configuration object which does not have overrides.
+    $config = \Drupal::configFactory()->getEditable('config_test.system');
+
+    // Verify that it does not contains the overridden data from $config.
+    $this->assertIdentical($config->get('foo'), $expected_original_data['foo']);
+    $this->assertIdentical($config->get('baz'), NULL);
+    $this->assertIdentical($config->get('404'), $expected_original_data['404']);
+
     // Set the value for 'baz' (on the original data).
     $expected_original_data['baz'] = 'original baz';
     $config->set('baz', $expected_original_data['baz']);
@@ -71,11 +79,6 @@ function testConfOverride() {
     $expected_original_data['404'] = 'original 404';
     $config->set('404', $expected_original_data['404']);
 
-    // Verify that it still contains the overridden data from $config.
-    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
-    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
-    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
-
     // Save the configuration object (having overrides applied).
     $config->save();
 
@@ -85,6 +88,11 @@ function testConfOverride() {
     $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
     $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
 
+    // Verify that raw config data has changed.
+    $this->assertIdentical($config->getOriginal('foo', FALSE), $expected_original_data['foo']);
+    $this->assertIdentical($config->getOriginal('baz', FALSE), $expected_original_data['baz']);
+    $this->assertIdentical($config->getOriginal('404', FALSE), $expected_original_data['404']);
+
     // Write file to staging.
     $staging = $this->container->get('config.storage.staging');
     $expected_new_data = array(
@@ -118,7 +126,7 @@ function testConfOverride() {
     $this->assertIdentical($config->get('key'), 'override');
     $old_state = \Drupal::configFactory()->getOverrideState();
     \Drupal::configFactory()->setOverrideState(FALSE);
-    $config_raw = \Drupal::config('config_test.new');
+    $config_raw = \Drupal::configFactory()->getEditable('config_test.new');
     $this->assertIdentical($config_raw->get('key'), NULL);
     $config_raw
       ->set('key', 'raw')
diff --git a/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php b/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
index 1fd05fa..0cf8f0b 100644
--- a/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
+++ b/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
@@ -41,7 +41,7 @@ public function testOverridePriorities() {
     /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
     $config_factory = $this->container->get('config.factory');
     $config_factory
-      ->get('system.site')
+      ->getEditable('system.site')
       ->set('name', $non_overridden_name)
       ->set('slogan', $non_overridden_slogan)
       ->set('mail', $non_overridden_mail)
diff --git a/core/modules/config/tests/config_test/src/SchemaListenerController.php b/core/modules/config/tests/config_test/src/SchemaListenerController.php
index baf2970..1a6b28c 100644
--- a/core/modules/config/tests/config_test/src/SchemaListenerController.php
+++ b/core/modules/config/tests/config_test/src/SchemaListenerController.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\config_test;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\Schema\SchemaIncompleteException;
 use Drupal\Core\Controller\ControllerBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Controller for testing \Drupal\Core\Config\Testing\ConfigSchemaChecker.
@@ -16,11 +18,30 @@
 class SchemaListenerController extends ControllerBase {
 
   /**
+   * Constructs the SchemaListenerController object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory) {
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('config.factory')
+    );
+  }
+
+  /**
    * Tests the WebTestBase tests can use strict schema checking.
    */
   public function test() {
     try {
-      $this->config('config_schema_test.schemaless')->set('foo', 'bar')->save();
+      $this->configFactory->getEditable('config_schema_test.schemaless')->set('foo', 'bar')->save();
     }
     catch (SchemaIncompleteException $e) {
       return [
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index 13bccd7..47a3bad 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -728,7 +728,7 @@ public function testTextFormatTranslation() {
     // security vulnerabilities.
     $config_factory
       ->setOverrideState(FALSE)
-      ->get('config_translation_test.content')
+      ->getEditable('config_translation_test.content')
       ->set('content.format', 'full_html')
       ->save();
 
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index 0ad6093..6764e81 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -181,7 +181,7 @@ function contact_user_profile_form_submit($form, FormStateInterface $form_state)
  *
  * Add the default personal contact setting on the user settings page.
  *
- * @see user_admin_settings()
+ * @see \Drupal\user\AccountSettingsForm
  */
 function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form_state) {
   $form['contact'] = array(
@@ -194,7 +194,7 @@ function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form
     '#type' => 'checkbox',
     '#title' => t('Enable the personal contact form by default for new users'),
     '#description' => t('Changing this setting will not affect existing users.'),
-    '#default_value' => \Drupal::config('contact.settings')->get('user_default_enabled'),
+    '#default_value' => \Drupal::configFactory()->getEditable('contact.settings')->get('user_default_enabled'),
   );
   // Add submit handler to save contact configuration.
   $form['#submit'][] = 'contact_form_user_admin_settings_submit';
@@ -206,7 +206,7 @@ function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form
  * @see contact_form_user_admin_settings_alter()
  */
 function contact_form_user_admin_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('contact.settings')
+  \Drupal::configFactory()->getEditable('contact.settings')
     ->set('user_default_enabled', $form_state->getValue('contact_default_status'))
     ->save();
 }
diff --git a/core/modules/contact/src/ContactFormEditForm.php b/core/modules/contact/src/ContactFormEditForm.php
index 123ba38..420be7d 100644
--- a/core/modules/contact/src/ContactFormEditForm.php
+++ b/core/modules/contact/src/ContactFormEditForm.php
@@ -7,14 +7,25 @@
 
 namespace Drupal\contact;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Base form for contact form edit forms.
  */
 class ContactFormEditForm extends EntityForm {
+  use ConfigFormBaseTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['contact.settings'];
+  }
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index e8568d4..570aaa4 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -98,7 +98,7 @@ function dblog_form_system_logging_settings_alter(&$form, FormStateInterface $fo
   $form['dblog_row_limit'] = array(
     '#type' => 'select',
     '#title' => t('Database log messages to keep'),
-    '#default_value' => \Drupal::config('dblog.settings')->get('row_limit'),
+    '#default_value' => \Drupal::configFactory()->getEditable('dblog.settings')->get('row_limit'),
     '#options' => array(0 => t('All')) + array_combine($row_limits, $row_limits),
     '#description' => t('The maximum number of messages to keep in the database log. Requires a cron maintenance task.', array('@cron' => \Drupal::url('system.status')))
   );
@@ -112,5 +112,5 @@ function dblog_form_system_logging_settings_alter(&$form, FormStateInterface $fo
  * @see dblog_form_system_logging_settings_alter()
  */
 function dblog_logging_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('dblog.settings')->set('row_limit', $form_state->getValue('dblog_row_limit'))->save();
+  \Drupal::configFactory()->getEditable('dblog.settings')->set('row_limit', $form_state->getValue('dblog_row_limit'))->save();
 }
diff --git a/core/modules/forum/src/ForumSettingsForm.php b/core/modules/forum/src/ForumSettingsForm.php
index 77f176d..f2b43c4 100644
--- a/core/modules/forum/src/ForumSettingsForm.php
+++ b/core/modules/forum/src/ForumSettingsForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['forum.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('forum.settings');
 
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index a21682b..358dd4a 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -339,7 +339,9 @@ function language_negotiation_url_prefixes_update() {
  * Saves language prefix settings.
  */
 function language_negotiation_url_prefixes_save(array $prefixes) {
-  \Drupal::config('language.negotiation')
+  // @todo https://www.drupal.org/node/2403229 $prefixes can contain
+  //   configuration overrides.
+  \Drupal::configFactory()->getEditable('language.negotiation')
   ->set('url.prefixes', $prefixes)
   ->save();
 }
@@ -355,7 +357,9 @@ function language_negotiation_url_domains() {
  * Saves the language domain settings.
  */
 function language_negotiation_url_domains_save(array $domains) {
-  \Drupal::config('language.negotiation')
+  // @todo https://www.drupal.org/node/2403229 $domains can contain
+  //   configuration overrides.
+  \Drupal::configFactory()->getEditable('language.negotiation')
   ->set('url.domains', $domains)
   ->save();
 }
@@ -445,19 +449,6 @@ function language_get_browser_drupal_langcode_mappings() {
 }
 
 /**
- * Stores language mappings between browser and Drupal language codes.
- *
- * @param array $mappings
- *   An array containing browser language codes as keys with corresponding
- *   Drupal language codes as values.
- */
-function language_set_browser_drupal_langcode_mappings($mappings) {
-  $config = \Drupal::config('language.mappings');
-  $config->setData($mappings);
-  $config->save();
-}
-
-/**
  * Implements hook_form_FORM_ID_alter for system_regional_settings().
  *
  * @see language_system_regional_settings_form_submit()
@@ -505,7 +496,7 @@ function language_form_alter(&$form, FormStateInterface $form_state) {
  * @see language_form_system_regional_settings_alter()
  */
 function language_system_regional_settings_form_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('system.site')->set('langcode', $form_state->getValue('site_default_language'))->save();
+  \Drupal::configFactory()->getEditable('system.site')->set('langcode', $form_state->getValue('site_default_language'))->save();
 }
 
 /**
diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php
index e17b3d2..beb4d11 100644
--- a/core/modules/language/src/ConfigurableLanguageManager.php
+++ b/core/modules/language/src/ConfigurableLanguageManager.php
@@ -195,7 +195,7 @@ public function getDefinedLanguageTypesInfo() {
    * {@inheritdoc}
    */
   public function saveLanguageTypesConfiguration(array $values) {
-    $config = $this->configFactory->get('language.types');
+    $config = $this->configFactory->getEditable('language.types');
     if (isset($values['configurable'])) {
       $config->set('configurable', $values['configurable']);
     }
@@ -355,7 +355,7 @@ public function updateLockedLanguageWeights() {
     // Loop locked languages to maintain the existing order.
     $locked_languages = $this->getLanguages(LanguageInterface::STATE_LOCKED);
     $config_ids = array_map(function($language) { return 'language.entity.' . $language->getId(); }, $locked_languages);
-    foreach ($this->configFactory->loadMultiple($config_ids) as $config) {
+    foreach ($this->configFactory->loadMultiple($config_ids, FALSE) as $config) {
       // Update system languages weight.
       $max_weight++;
       $config->set('weight', $max_weight);
diff --git a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
index aa8fbea..5e511b6 100644
--- a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
@@ -7,9 +7,11 @@
 
 namespace Drupal\language\Form;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -64,7 +66,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
 
     if (array_key_exists($this->browserLangcode, $mappings)) {
       unset($mappings[$this->browserLangcode]);
-      language_set_browser_drupal_langcode_mappings($mappings);
+      $this->configFactory()->getEditable('language.mappings')
+        ->clear($this->browserLangcode)
+        ->save();
 
       $args = array(
         '%browser' => $this->browserLangcode,
diff --git a/core/modules/language/src/Form/NegotiationBrowserForm.php b/core/modules/language/src/Form/NegotiationBrowserForm.php
index 8cbac11..eb2f0b7 100644
--- a/core/modules/language/src/Form/NegotiationBrowserForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
@@ -56,6 +56,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['language.mappings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = array();
 
diff --git a/core/modules/language/src/Form/NegotiationConfigureForm.php b/core/modules/language/src/Form/NegotiationConfigureForm.php
index ca20801..d9cf420 100644
--- a/core/modules/language/src/Form/NegotiationConfigureForm.php
+++ b/core/modules/language/src/Form/NegotiationConfigureForm.php
@@ -121,6 +121,13 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['language.types'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $configurable = $this->languageTypes->get('configurable');
 
diff --git a/core/modules/language/src/Form/NegotiationSelectedForm.php b/core/modules/language/src/Form/NegotiationSelectedForm.php
index 5b5d5a9..57194f9 100644
--- a/core/modules/language/src/Form/NegotiationSelectedForm.php
+++ b/core/modules/language/src/Form/NegotiationSelectedForm.php
@@ -26,6 +26,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('language.negotiation');
     $form['selected_langcode'] = array(
diff --git a/core/modules/language/src/Form/NegotiationSessionForm.php b/core/modules/language/src/Form/NegotiationSessionForm.php
index a0bd777..fff1dd5 100644
--- a/core/modules/language/src/Form/NegotiationSessionForm.php
+++ b/core/modules/language/src/Form/NegotiationSessionForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('language.negotiation');
     $form['language_negotiation_session_param'] = array(
diff --git a/core/modules/language/src/Form/NegotiationUrlForm.php b/core/modules/language/src/Form/NegotiationUrlForm.php
index dcb721a..bf7ce2a 100644
--- a/core/modules/language/src/Form/NegotiationUrlForm.php
+++ b/core/modules/language/src/Form/NegotiationUrlForm.php
@@ -26,6 +26,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     global $base_url;
     $config = $this->config('language.negotiation');
diff --git a/core/modules/language/src/LanguageNegotiator.php b/core/modules/language/src/LanguageNegotiator.php
index 930248c..0c00f2f 100644
--- a/core/modules/language/src/LanguageNegotiator.php
+++ b/core/modules/language/src/LanguageNegotiator.php
@@ -286,7 +286,7 @@ function saveConfiguration($type, $enabled_methods) {
         unset($enabled_methods[$method_id]);
       }
     }
-    $this->configFactory->get('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save();
+    $this->configFactory->getEditable('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save();
   }
 
   /**
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index 0a89198..2ca1ff5 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -45,10 +45,11 @@ function language_test_language_types_info_alter(array &$language_types) {
     unset($language_types[LanguageInterface::TYPE_CONTENT]['fixed']);
     // By default languages are not configurable. Make
     // LanguageInterface::TYPE_CONTENT configurable.
-    $configurable = \Drupal::config('language.types')->get('configurable');
+    $config = \Drupal::configFactory()->getEditable('language.types');
+    $configurable = $config->get('configurable');
     if (!in_array(LanguageInterface::TYPE_CONTENT, $configurable)) {
       $configurable[] = LanguageInterface::TYPE_CONTENT;
-      \Drupal::config('language.types')->set('configurable', $configurable)->save();
+      $config->set('configurable', $configurable)->save();
     }
   }
 }
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 8aa8d82..81aadf5 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -16,7 +16,7 @@ function locale_install() {
   // Create the interface translations directory and ensure it's writable.
   if (!$directory = \Drupal::config('locale.settings')->get('translation.path')) {
     $directory = conf_path() . '/files/translations';
-    \Drupal::config('locale.settings')->set('translation.path', $directory)->save();
+    \Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save();
   }
   file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
 }
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 9e09a46..79b2a50 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -647,7 +647,7 @@ function locale_form_language_admin_edit_form_alter(&$form, FormStateInterface $
     $form['locale_translate_english'] = array(
       '#title' => t('Enable interface translation to English'),
       '#type' => 'checkbox',
-      '#default_value' => locale_translate_english(),
+      '#default_value' => \Drupal::configFactory()->getEditable('locale.settings')->get('translate_english'),
     );
     $form['actions']['submit']['#submit'][] = 'locale_form_language_admin_edit_form_alter_submit';
   }
@@ -657,7 +657,7 @@ function locale_form_language_admin_edit_form_alter(&$form, FormStateInterface $
  * Form submission handler for language_admin_edit_form().
  */
 function locale_form_language_admin_edit_form_alter_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('locale.settings')->set('translate_english', intval($form_state->getValue('locale_translate_english')))->save();
+  \Drupal::configFactory()->getEditable('locale.settings')->set('translate_english', intval($form_state->getValue('locale_translate_english')))->save();
 }
 
 /**
@@ -665,6 +665,8 @@ function locale_form_language_admin_edit_form_alter_submit($form, FormStateInter
  *
  * @return bool
  *   Returns TRUE if content should be translated to English, FALSE otherwise.
+ *
+ * @fixme remove this method
  */
 function locale_translate_english() {
   return \Drupal::config('locale.settings')->get('translate_english');
diff --git a/core/modules/locale/src/Form/LocaleSettingsForm.php b/core/modules/locale/src/Form/LocaleSettingsForm.php
index 16c2087..4ff2c33 100644
--- a/core/modules/locale/src/Form/LocaleSettingsForm.php
+++ b/core/modules/locale/src/Form/LocaleSettingsForm.php
@@ -24,6 +24,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['locale.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('locale.settings');
 
diff --git a/core/modules/locale/src/Tests/LocaleUpdateBase.php b/core/modules/locale/src/Tests/LocaleUpdateBase.php
index 4a92a30..7e17c89 100644
--- a/core/modules/locale/src/Tests/LocaleUpdateBase.php
+++ b/core/modules/locale/src/Tests/LocaleUpdateBase.php
@@ -60,7 +60,7 @@ protected function setUp() {
     // Update module should not go out to d.o to check for updates. We override
     // the url to the default update_test xml path. But without providing
     // a mock xml file, no update data will be found.
-    \Drupal::config('update.settings')->set('fetch.url', _url('update-test', array('absolute' => TRUE)))->save();
+    $this->config('update.settings')->set('fetch.url', _url('update-test', array('absolute' => TRUE)))->save();
 
     // Setup timestamps to identify old and new translation sources.
     $this->timestampOld = REQUEST_TIME - 300;
@@ -70,7 +70,7 @@ protected function setUp() {
 
     // Enable import of translations. By default this is disabled for automated
     // tests.
-    \Drupal::config('locale.settings')
+    $this->config('locale.settings')
       ->set('translation.import_enabled', TRUE)
       ->save();
   }
@@ -84,7 +84,7 @@ protected function setUp() {
    */
   protected function setTranslationsDirectory($path) {
     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
-    \Drupal::config('locale.settings')->set('translation.path', $path)->save();
+    $this->config('locale.settings')->set('translation.path', $path)->save();
   }
 
   /**
@@ -180,7 +180,7 @@ protected function makePoFile($path, $filename, $timestamp = NULL, array $transl
    * imported.
    */
   protected function setTranslationFiles() {
-    $config = \Drupal::config('locale.settings');
+    $config = $this->config('locale.settings');
 
     // A flag is set to let the locale_test module replace the project data with
     // a set of test projects which match the below project files.
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Config.php b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
index a7b5de2..7d84813 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Config.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
@@ -6,6 +6,7 @@
 
 namespace Drupal\migrate\Plugin\migrate\destination;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\MigrateException;
@@ -43,12 +44,12 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface
    *   The plugin implementation definition.
    * @param \Drupal\migrate\Entity\MigrationInterface $migration
    *   The migration entity.
-   * @param \Drupal\Core\Config\Config $config
-   *   The configuration object.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ConfigObject $config) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ConfigFactoryInterface $config_factory) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
-    $this->config = $config;
+    $this->config = $config_factory->getEditable($configuration['config_name']);
   }
 
   /**
@@ -60,7 +61,7 @@ public static function create(ContainerInterface $container, array $configuratio
       $plugin_id,
       $plugin_definition,
       $migration,
-      $container->get('config.factory')->get($configuration['config_name'])
+      $container->get('config.factory')
     );
   }
 
diff --git a/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php b/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
index 8ed3f6d..6b7dcd7 100644
--- a/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
+++ b/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
@@ -37,13 +37,18 @@ public function testImport() {
     }
     $config->expects($this->once())
       ->method('save');
+    $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
+    $config_factory->expects($this->once())
+      ->method('getEditable')
+      ->with('d8_config')
+      ->will($this->returnValue($config));
     $row = $this->getMockBuilder('Drupal\migrate\Row')
       ->disableOriginalConstructor()
       ->getMock();
     $row->expects($this->once())
       ->method('getRawDestination')
       ->will($this->returnValue($source));
-    $destination = new Config(array(), 'd8_config', array('pluginId' => 'd8_config'), $migration, $config);
+    $destination = new Config(array('config_name' => 'd8_config'), 'd8_config', array('pluginId' => 'd8_config'), $migration, $config_factory);
     $destination->import($row);
   }
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index ad63d21..976ca29 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -841,7 +841,7 @@ function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $fo
   $form['admin_theme']['use_admin_theme'] = array(
     '#type' => 'checkbox',
     '#title' => t('Use the administration theme when editing or creating content'),
-    '#default_value' => \Drupal::config('node.settings')->get('use_admin_theme'),
+    '#default_value' => \Drupal::configFactory()->getEditable('node.settings')->get('use_admin_theme'),
   );
   $form['#submit'][] = 'node_form_system_themes_admin_form_submit';
 }
@@ -852,7 +852,7 @@ function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $fo
  * @see node_form_system_themes_admin_form_alter()
  */
 function node_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('node.settings')
+  \Drupal::configFactory()->getEditable('node.settings')
     ->set('use_admin_theme', $form_state->getValue('use_admin_theme'))
     ->save();
   \Drupal::service('router.builder_indicator')->setRebuildNeeded();
diff --git a/core/modules/search/src/SearchPageListBuilder.php b/core/modules/search/src/SearchPageListBuilder.php
index 6310dae..7180b8f 100644
--- a/core/modules/search/src/SearchPageListBuilder.php
+++ b/core/modules/search/src/SearchPageListBuilder.php
@@ -328,7 +328,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
-    $search_settings = $this->configFactory->get('search.settings');
+    $search_settings = $this->configFactory->getEditable('search.settings');
     // If these settings change, the default index needs to be rebuilt.
     if (($search_settings->get('index.minimum_word_size') != $form_state->getValue('minimum_word_size')) || ($search_settings->get('index.overlap_cjk') != $form_state->getValue('overlap_cjk'))) {
       $search_settings->set('index.minimum_word_size', $form_state->getValue('minimum_word_size'));
diff --git a/core/modules/search/src/SearchPageRepository.php b/core/modules/search/src/SearchPageRepository.php
index 3dfdfb2..66f7bda 100644
--- a/core/modules/search/src/SearchPageRepository.php
+++ b/core/modules/search/src/SearchPageRepository.php
@@ -94,14 +94,14 @@ public function getDefaultSearchPage() {
    * {@inheritdoc}
    */
   public function clearDefaultSearchPage() {
-    $this->configFactory->get('search.settings')->clear('default_page')->save();
+    $this->configFactory->getEditable('search.settings')->clear('default_page')->save();
   }
 
   /**
    * {@inheritdoc}
    */
   public function setDefaultSearchPage(SearchPageInterface $search_page) {
-    $this->configFactory->get('search.settings')->set('default_page', $search_page->id())->save();
+    $this->configFactory->getEditable('search.settings')->set('default_page', $search_page->id())->save();
     $search_page->enable()->save();
   }
 
diff --git a/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php b/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
index 3ff112e..767a81b 100644
--- a/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
+++ b/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
@@ -151,7 +151,7 @@ public function testClearDefaultSearchPage() {
       ->with('default_page')
       ->will($this->returnValue($config));
     $this->configFactory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->with('search.settings')
       ->will($this->returnValue($config));
     $this->searchPageRepository->clearDefaultSearchPage();
@@ -227,7 +227,7 @@ public function testSetDefaultSearchPage() {
       ->method('save')
       ->will($this->returnValue($config));
     $this->configFactory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->with('search.settings')
       ->will($this->returnValue($config));
 
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index d716a03..41a78a2 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -56,7 +56,7 @@ function shortcut_install() {
   // Theme settings are not configuration entities and cannot depend on modules
   // so to set a module-specific setting, we need to set it with logic.
   if (\Drupal::service('theme_handler')->themeExists('seven')) {
-    \Drupal::config('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
+    \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
   }
 }
 
@@ -67,6 +67,6 @@ function shortcut_uninstall() {
   // Theme settings are not configuration entities and cannot depend on modules
   // so to unset a module-specific setting, we need to unset it with logic.
   if (\Drupal::service('theme_handler')->themeExists('seven')) {
-    \Drupal::config('seven.settings')->clear('third_party_settings.shortcut.module_link')->save();
+    \Drupal::configFactory()->getEditable('seven.settings')->clear('third_party_settings.shortcut.module_link')->save();
   }
 }
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index ba9c43d..88c64dd 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -405,7 +405,7 @@ function shortcut_themes_installed($theme_list) {
     // Theme settings are not configuration entities and cannot depend on modules
     // so to set a module-specific setting, we need to set it with logic.
     if (\Drupal::moduleHandler()->moduleExists('shortcut')) {
-      \Drupal::config('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
+      \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
     }
   }
 }
diff --git a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
index d4e7197..e6d4d4d 100644
--- a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['simpletest.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('simpletest.settings');
     $form['general'] = array(
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index d87718e..11e9076 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -160,7 +160,7 @@ protected function setUp() {
 
     // Manually configure the test mail collector implementation to prevent
     // tests from sending out e-mails and collect them in state instead.
-    $config->get('system.mail')
+    $config->getEditable('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index 1ce9eef..f21ffb3 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -202,7 +202,10 @@ protected function setUp() {
     if ($modules) {
       $this->enableModules($modules);
     }
-    // In order to use theme functions default theme config needs to exist.
+    // In order to use theme functions default theme config needs to exist. This
+    // configuration is not actually saved because it does not need to be. If it
+    // was saved then all KernelTestBase tests would need to install the system
+    // module of the schema would be missing.
     $this->config('system.theme')->set('default', 'classy');
 
     // Tests based on this class are entitled to use Drupal's File and
@@ -477,7 +480,7 @@ protected function disableModules(array $modules) {
     // Unset the list of modules in the extension handler.
     $module_handler = $this->container->get('module_handler');
     $module_filenames = $module_handler->getModuleList();
-    $extension_config = $this->container->get('config.factory')->get('core.extension');
+    $extension_config = $this->config('core.extension');
     foreach ($modules as $module) {
       unset($module_filenames[$module]);
       $extension_config->clear('module.' . $module);
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 7eaf71b..cfcfdbc 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1629,7 +1629,7 @@ protected function config($name) {
     $config_factory = \Drupal::configFactory();
     $old_state = $config_factory->getOverrideState();
     $config_factory->setOverrideState(FALSE);
-    $config = $config_factory->get($name);
+    $config = $config_factory->getEditable($name);
     $config_factory->setOverrideState($old_state);
     return $config;
   }
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index ec190a0..860842d 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -889,7 +889,7 @@ protected function setUp() {
     // UI. If declared in settings.php, they would no longer be configurable.
     file_prepare_directory($this->privateFilesDirectory, FILE_CREATE_DIRECTORY);
     file_prepare_directory($this->tempFilesDirectory, FILE_CREATE_DIRECTORY);
-    $config->get('system.file')
+    $config->getEditable('system.file')
       ->set('path.temporary', $this->tempFilesDirectory)
       ->save();
 
@@ -897,7 +897,7 @@ protected function setUp() {
     // tests from sending out emails and collect them in state instead.
     // While this should be enforced via settings.php prior to installation,
     // some tests expect to be able to test mail system implementations.
-    $config->get('system.mail')
+    $config->getEditable('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
@@ -905,10 +905,10 @@ protected function setUp() {
     // environment optimizations for all tests to avoid needless overhead and
     // ensure a sane default experience for test authors.
     // @see https://drupal.org/node/2259167
-    $config->get('system.logging')
+    $config->getEditable('system.logging')
       ->set('error_level', 'verbose')
       ->save();
-    $config->get('system.performance')
+    $config->getEditable('system.performance')
       ->set('css.preprocess', FALSE)
       ->set('js.preprocess', FALSE)
       ->save();
diff --git a/core/modules/statistics/src/StatisticsSettingsForm.php b/core/modules/statistics/src/StatisticsSettingsForm.php
index 47411d7..2213bef 100644
--- a/core/modules/statistics/src/StatisticsSettingsForm.php
+++ b/core/modules/statistics/src/StatisticsSettingsForm.php
@@ -58,6 +58,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['statistics.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('statistics.settings');
 
diff --git a/core/modules/syslog/syslog.install b/core/modules/syslog/syslog.install
index 8a2350a..e3377c8 100644
--- a/core/modules/syslog/syslog.install
+++ b/core/modules/syslog/syslog.install
@@ -11,5 +11,5 @@
 function syslog_install() {
   // The default facility setting depends on the operating system, so it needs
   // to be set dynamically during installation.
-  \Drupal::config('syslog.settings')->set('facility', defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER)->save();
+  \Drupal::configFactory()->getEditable('syslog.settings')->set('facility', defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER)->save();
 }
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index aad4060..61873f9 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -33,7 +33,7 @@ function syslog_help($route_name, RouteMatchInterface $route_match) {
  * Implements hook_form_FORM_ID_alter().
  */
 function syslog_form_system_logging_settings_alter(&$form, FormStateInterface $form_state) {
-  $config = \Drupal::config('syslog.settings');
+  $config = \Drupal::configFactory()->getEditable('syslog.settings');
   $help = \Drupal::moduleHandler()->moduleExists('help') ? ' ' . \Drupal::l(t('More information'), new Url('help.page', ['name' => 'syslog'])) . '.' : NULL;
   $form['syslog_identity'] = array(
     '#type'          => 'textfield',
@@ -66,7 +66,7 @@ function syslog_form_system_logging_settings_alter(&$form, FormStateInterface $f
  * @see syslog_form_system_logging_settings_alter()
  */
 function syslog_logging_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('syslog.settings')
+  \Drupal::configFactory()->getEditable('syslog.settings')
     ->set('identity', $form_state->getValue('syslog_identity'))
     ->set('facility', $form_state->getValue('syslog_facility'))
     ->set('format', $form_state->getValue('syslog_format'))
diff --git a/core/modules/system/src/Controller/ThemeController.php b/core/modules/system/src/Controller/ThemeController.php
index 3bb6d31..26083cb 100644
--- a/core/modules/system/src/Controller/ThemeController.php
+++ b/core/modules/system/src/Controller/ThemeController.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Controller;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
@@ -40,10 +41,13 @@ class ThemeController extends ControllerBase {
    *   The theme handler.
    * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder_indicator
    *   The route builder.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    */
-  public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIndicatorInterface $route_builder_indicator) {
+  public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIndicatorInterface $route_builder_indicator, ConfigFactoryInterface $config_factory) {
     $this->themeHandler = $theme_handler;
     $this->routeBuilderIndicator = $route_builder_indicator;
+    $this->configFactory = $config_factory;
   }
 
   /**
@@ -52,7 +56,8 @@ public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIn
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('theme_handler'),
-      $container->get('router.builder_indicator')
+      $container->get('router.builder_indicator'),
+      $container->get('config.factory')
     );
   }
 
@@ -142,7 +147,7 @@ public function install(Request $request) {
    *   Throws access denied when no theme is set in the request.
    */
   public function setDefaultTheme(Request $request) {
-    $config = $this->config('system.theme');
+    $config = $this->configFactory->getEditable('system.theme');
     $theme = $request->query->get('theme');
 
     if (isset($theme)) {
diff --git a/core/modules/system/src/Form/CronForm.php b/core/modules/system/src/Form/CronForm.php
index cfb82fd..f906c70 100644
--- a/core/modules/system/src/Form/CronForm.php
+++ b/core/modules/system/src/Form/CronForm.php
@@ -83,6 +83,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.cron'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.cron');
 
diff --git a/core/modules/system/src/Form/FileSystemForm.php b/core/modules/system/src/Form/FileSystemForm.php
index 8cf5eb3..368f318 100644
--- a/core/modules/system/src/Form/FileSystemForm.php
+++ b/core/modules/system/src/Form/FileSystemForm.php
@@ -74,6 +74,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.file'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.file');
     $form['file_public_path'] = array(
diff --git a/core/modules/system/src/Form/ImageToolkitForm.php b/core/modules/system/src/Form/ImageToolkitForm.php
index 6eeaa4e..0d9bec9 100644
--- a/core/modules/system/src/Form/ImageToolkitForm.php
+++ b/core/modules/system/src/Form/ImageToolkitForm.php
@@ -61,6 +61,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.image'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $current_toolkit = $this->config('system.image')->get('toolkit');
 
diff --git a/core/modules/system/src/Form/LoggingForm.php b/core/modules/system/src/Form/LoggingForm.php
index 500fed0..cfbbddc 100644
--- a/core/modules/system/src/Form/LoggingForm.php
+++ b/core/modules/system/src/Form/LoggingForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.logging'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.logging');
     $form['error_level'] = array(
diff --git a/core/modules/system/src/Form/PerformanceForm.php b/core/modules/system/src/Form/PerformanceForm.php
index 372b319..9049c78 100644
--- a/core/modules/system/src/Form/PerformanceForm.php
+++ b/core/modules/system/src/Form/PerformanceForm.php
@@ -93,6 +93,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.performance'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#attached']['library'][] = 'system/drupal.system';
 
diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php
index 2d3934f..827f74f 100644
--- a/core/modules/system/src/Form/RegionalForm.php
+++ b/core/modules/system/src/Form/RegionalForm.php
@@ -58,6 +58,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.date'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $countries = $this->countryManager->getList();
     $system_date = $this->config('system.date');
diff --git a/core/modules/system/src/Form/RssFeedsForm.php b/core/modules/system/src/Form/RssFeedsForm.php
index 84f18fa..cde9964 100644
--- a/core/modules/system/src/Form/RssFeedsForm.php
+++ b/core/modules/system/src/Form/RssFeedsForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.rss'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $rss_config = $this->config('system.rss');
     $form['feed_description'] = array(
diff --git a/core/modules/system/src/Form/SiteInformationForm.php b/core/modules/system/src/Form/SiteInformationForm.php
index f2efcd5..71a0fbd 100644
--- a/core/modules/system/src/Form/SiteInformationForm.php
+++ b/core/modules/system/src/Form/SiteInformationForm.php
@@ -71,6 +71,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.site'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $site_config = $this->config('system.site');
     $site_mail = $site_config->get('mail');
diff --git a/core/modules/system/src/Form/SiteMaintenanceModeForm.php b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
index b87533e..cde1f57 100644
--- a/core/modules/system/src/Form/SiteMaintenanceModeForm.php
+++ b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
@@ -57,6 +57,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.maintenance'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.maintenance');
     $form['maintenance_mode'] = array(
diff --git a/core/modules/system/src/Form/ThemeAdminForm.php b/core/modules/system/src/Form/ThemeAdminForm.php
index 93cace8..9aa7123 100644
--- a/core/modules/system/src/Form/ThemeAdminForm.php
+++ b/core/modules/system/src/Form/ThemeAdminForm.php
@@ -24,6 +24,13 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['system.theme'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state, array $theme_options = NULL) {
     // Administration theme settings.
     $form['admin_theme'] = array(
diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php
index 8e72246..50f7464 100644
--- a/core/modules/system/src/Form/ThemeSettingsForm.php
+++ b/core/modules/system/src/Form/ThemeSettingsForm.php
@@ -30,6 +30,13 @@ class ThemeSettingsForm extends ConfigFormBase {
   protected $moduleHandler;
 
   /**
+   * An array of configuration names that should be editable.
+   *
+   * @var array
+   */
+  protected $editableConfig = [];
+
+  /**
    * Constructs a ThemeSettingsForm object.
    *
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
@@ -62,6 +69,13 @@ public function getFormId() {
 
   /**
    * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return $this->editableConfig;
+  }
+
+  /**
+   * {@inheritdoc}
    *
    * @param string $theme
    *   The theme name.
@@ -87,6 +101,10 @@ public function buildForm(array $form, FormStateInterface $form_state, $theme =
       $var = 'theme_settings';
       $config_key = 'system.theme.global';
     }
+    // @todo this is pretty meaningless since we're using theme_get_settings
+    //   which means overrides can bleed into active config here. Will be fixed
+    //   by https://www.drupal.org/node/2402467.
+    $this->editableConfig = [$config_key];
 
     $form['var'] = array(
       '#type' => 'hidden',
@@ -377,7 +395,9 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
-    $config = $this->config($form_state->getValue('config_key'));
+    $config_key = $form_state->getValue('config_key');
+    $this->editableConfig = [$config_key];
+    $config = $this->config($config_key);
 
     // Exclude unnecessary elements before saving.
     $form_state->cleanValues();
diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index 7aa56d0..d16330f 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -104,7 +104,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
       '#min' => 0,
       '#max' => 100,
-      '#default_value' => $this->configFactory->get('system.image.gd')->get('jpeg_quality'),
+      '#default_value' => $this->configFactory->getEditable('system.image.gd')->get('jpeg_quality', FALSE),
       '#field_suffix' => t('%'),
     );
     return $form;
@@ -114,7 +114,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configFactory->get('system.image.gd')
+    $this->configFactory->getEditable('system.image.gd')
       ->set('jpeg_quality', $form_state->getValue(array('gd', 'image_jpeg_quality')))
       ->save();
   }
diff --git a/core/modules/system/src/Tests/Form/FormObjectTest.php b/core/modules/system/src/Tests/Form/FormObjectTest.php
index 237d9e7..a732e96 100644
--- a/core/modules/system/src/Tests/Form/FormObjectTest.php
+++ b/core/modules/system/src/Tests/Form/FormObjectTest.php
@@ -27,7 +27,7 @@ class FormObjectTest extends SystemConfigFormTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->form = new FormTestObject();
+    $this->form = new FormTestObject($this->container->get('config.factory'));
     $this->values = array(
       'bananas' => array(
         '#value' => $this->randomString(10),
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index c9ae4c1..3b880ca 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -623,7 +623,7 @@ function system_install() {
   \Drupal::state()->set('system.cron_key', $cron_key);
 
   // Populate the site UUID.
-  \Drupal::config('system.site')
+  \Drupal::configFactory()->getEditable('system.site')
     ->set('uuid', \Drupal::service('uuid')->generate())
     ->save();
 }
diff --git a/core/modules/system/tests/modules/form_test/form_test.services.yml b/core/modules/system/tests/modules/form_test/form_test.services.yml
index 472e0bc..24513a6 100644
--- a/core/modules/system/tests/modules/form_test/form_test.services.yml
+++ b/core/modules/system/tests/modules/form_test/form_test.services.yml
@@ -1,6 +1,7 @@
 services:
   form_test.form.serviceform:
     class: Drupal\form_test\FormTestServiceObject
+    arguments: ['@config.factory']
   form_test.event_subscriber:
     class: Drupal\form_test\EventSubscriber\FormTestEventSubscriber
     tags:
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
index da7b4d5..9dc522c 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
@@ -8,13 +8,13 @@
 namespace Drupal\form_test;
 
 use Drupal\Component\Utility\String;
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object that needs arguments.
  */
-class FormTestArgumentsObject extends FormBase {
+class FormTestArgumentsObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -26,6 +26,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state, $arg = NULL) {
     $form['element'] = array('#markup' => 'The FormTestArgumentsObject::buildForm() method was used for this form.');
 
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
index a3e5064..47e5169 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a test form object.
  */
-class FormTestControllerObject extends FormBase {
+class FormTestControllerObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -26,9 +26,18 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public static function create(ContainerInterface $container) {
     drupal_set_message(t('The FormTestControllerObject::create() method was used for this form.'));
-    return new static();
+    return new static(
+      $container->get('config.factory')
+    );
   }
 
   /**
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestObject.php b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
index 4669bfe..73f273e 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
  */
-class FormTestObject extends FormBase {
+class FormTestObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form['element'] = array('#markup' => 'The FormTestObject::buildForm() method was used for this form.');
 
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
index de4e6c0..c60b6d1 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
  */
-class FormTestServiceObject extends FormBase {
+class FormTestServiceObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form['element'] = array('#markup' => 'The FormTestServiceObject::buildForm() method was used for this form.');
 
@@ -54,7 +61,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestServiceObject::submitForm() method was used for this form.'));
-    $this->config('form_test.object')
+    $this->config('form_test.object', FALSE)
       ->set('bananas', $form_state->getValue('bananas'))
       ->save();
   }
diff --git a/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php b/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
index 45efda7..243a81b 100644
--- a/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
+++ b/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
@@ -21,4 +21,11 @@ public function getFormId() {
     return 'form_test_system_config_test_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return [];
+  }
+
 }
diff --git a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
index f72eaaa..7513ac2 100644
--- a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
+++ b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
@@ -103,7 +103,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       '#description' => $this->t('A toolkit parameter for testing purposes.'),
       '#min' => 0,
       '#max' => 100,
-      '#default_value' => $this->configFactory->get('system.image.test_toolkit')->get('test_parameter'),
+      '#default_value' => $this->configFactory->getEditable('system.image.test_toolkit')->get('test_parameter', FALSE),
     );
     return $form;
   }
@@ -121,7 +121,7 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configFactory->get('system.image.test_toolkit')
+    $this->configFactory->getEditable('system.image.test_toolkit')
       ->set('test_parameter', $form_state->getValue(array('test', 'test_parameter')))
       ->save();
   }
diff --git a/core/modules/update/src/UpdateSettingsForm.php b/core/modules/update/src/UpdateSettingsForm.php
index 81ef7e0..7e4664d 100644
--- a/core/modules/update/src/UpdateSettingsForm.php
+++ b/core/modules/update/src/UpdateSettingsForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['update.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('update.settings');
 
diff --git a/core/modules/user/src/AccountSettingsForm.php b/core/modules/user/src/AccountSettingsForm.php
index bce6a60..2b91877 100644
--- a/core/modules/user/src/AccountSettingsForm.php
+++ b/core/modules/user/src/AccountSettingsForm.php
@@ -59,6 +59,17 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return [
+      'system.site',
+      'user.mail',
+      'user.settings',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $config = $this->config('user.settings');
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index a251fd7..a73a3a8 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1374,7 +1374,7 @@ function user_modules_uninstalled($modules) {
   \Drupal::service('user.data')->delete($modules);
   // User signatures require Filter module.
   if (in_array('filter', $modules)) {
-    \Drupal::config('user.settings')->set('signatures', FALSE)->save();
+    \Drupal::configFactory()->getEditable('user.settings')->set('signatures', FALSE)->save();
   }
 }
 
diff --git a/core/modules/views/tests/modules/views_test_data/views_test_data.install b/core/modules/views/tests/modules/views_test_data/views_test_data.install
index 8cd7f38..eeb5faa 100644
--- a/core/modules/views/tests/modules/views_test_data/views_test_data.install
+++ b/core/modules/views/tests/modules/views_test_data/views_test_data.install
@@ -31,5 +31,5 @@ function views_test_data_install() {
     'em' => 'EM',
     'marquee' => 'MARQUEE'
   );
-  \Drupal::config('views.settings')->set('field_rewrite_elements', $values)->save();
+  \Drupal::configFactory()->getEditable('views.settings')->set('field_rewrite_elements', $values)->save();
 }
diff --git a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
index a9ffd6f..d8cd1e2 100644
--- a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
+++ b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
@@ -26,6 +26,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['views.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
diff --git a/core/modules/views_ui/src/Form/BasicSettingsForm.php b/core/modules/views_ui/src/Form/BasicSettingsForm.php
index 621f1a4..91b8d60 100644
--- a/core/modules/views_ui/src/Form/BasicSettingsForm.php
+++ b/core/modules/views_ui/src/Form/BasicSettingsForm.php
@@ -25,6 +25,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
+  protected function getEditableConfigNames() {
+    return ['views.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
diff --git a/core/profiles/minimal/minimal.install b/core/profiles/minimal/minimal.install
index 52bea38..a8baf07 100644
--- a/core/profiles/minimal/minimal.install
+++ b/core/profiles/minimal/minimal.install
@@ -13,8 +13,8 @@
  */
 function minimal_install() {
   // Disable the user pictures on nodes.
-  \Drupal::config('system.theme.global')->set('features.node_user_picture', FALSE)->save();
+  \Drupal::configFactory()->getEditable('system.theme.global')->set('features.node_user_picture', FALSE)->save();
 
   // Allow visitor account creation, but with administrative approval.
-  \Drupal::config('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
+  \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
 }
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 645587b..f571667 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -22,10 +22,10 @@ function standard_install() {
   \Drupal::service('entity.definition_update_manager')->applyUpdates();
 
   // Set front page to "node".
-  \Drupal::config('system.site')->set('page.front', 'node')->save();
+  \Drupal::configFactory()->getEditable('system.site')->set('page.front', 'node')->save();
 
   // Allow visitor account creation with administrative approval.
-  $user_settings = \Drupal::config('user.settings');
+  $user_settings = \Drupal::configFactory()->getEditable('user.settings');
   $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
 
   // Enable default permissions for system roles.
@@ -71,5 +71,5 @@ function standard_install() {
   $shortcut->save();
 
   // Enable the admin theme.
-  \Drupal::config('node.settings')->set('use_admin_theme', '1')->save();
+  \Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', '1')->save();
 }
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
index 13438a8..112f85f 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
@@ -246,11 +246,16 @@ public function testSaveInsert(EntityInterface $entity) {
         $this->entityTypeId . '_list', // List cache tag.
       ));
 
-    $this->configFactory->expects($this->exactly(2))
+    $this->configFactory->expects($this->exactly(1))
       ->method('get')
       ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
 
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
     $this->moduleHandler->expects($this->at(0))
       ->method('invokeAll')
       ->with('test_entity_type_presave');
@@ -310,10 +315,14 @@ public function testSaveUpdate(EntityInterface $entity) {
       ->method('loadMultiple')
       ->with(array('the_config_prefix.foo'))
       ->will($this->returnValue(array()));
-    $this->configFactory->expects($this->exactly(2))
+    $this->configFactory->expects($this->exactly(1))
       ->method('get')
       ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
 
     $this->moduleHandler->expects($this->at(0))
       ->method('invokeAll')
@@ -368,6 +377,10 @@ public function testSaveRename(ConfigEntityInterface $entity) {
 
     $this->configFactory->expects($this->once())
       ->method('rename')
+      ->willReturn($this->configFactory);
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.bar')
       ->will($this->returnValue($config_object));
     $this->configFactory->expects($this->exactly(2))
       ->method('loadMultiple')
@@ -504,8 +517,11 @@ public function testSaveNoMismatch() {
       ->will($this->returnValue($config_object));
     $this->configFactory->expects($this->once())
       ->method('rename')
+      ->willReturn($this->configFactory);
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
-
     $this->entityQuery->expects($this->once())
       ->method('condition')
       ->will($this->returnSelf());
@@ -734,7 +750,7 @@ public function testDelete() {
       ));
 
     $this->configFactory->expects($this->exactly(2))
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValueMap($config_map));
 
     $this->moduleHandler->expects($this->at(0))
diff --git a/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php b/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php
new file mode 100644
index 0000000..8b0bbf8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php
@@ -0,0 +1,70 @@
+getMock('Drupal\Core\Config\StorageInterface');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+    $typed_config = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
+    $this->config = new ImmutableConfig('test', $storage, $event_dispatcher, $typed_config);
+  }
+
+  /**
+   * @covers ::set
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not set values on immutable configuration test:name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testSet() {
+    $this->config->set('name', 'value');
+  }
+
+  /**
+   * @covers ::clear
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not clear name key in immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testClear() {
+    $this->config->clear('name');
+  }
+
+  /**
+   * @covers ::save
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not save immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testSave() {
+    $this->config->save();
+  }
+
+  /**
+   * @covers ::delete
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not delete immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testDelete() {
+    $this->config->delete();
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php b/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php
new file mode 100644
index 0000000..443646b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php
@@ -0,0 +1,76 @@
+getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    // Set up some configuration in a mocked config factory.
+    $trait->configFactory = $this->getConfigFactoryStub([
+      'editable.config' => [],
+      'immutable.config' => []
+    ]);
+
+    $trait->expects($this->any())
+      ->method('getEditableConfigNames')
+      ->willReturn(['editable.config']);
+
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // Ensure that configuration that is expected to be mutable is.
+    $result = $config_method->invoke($trait, 'editable.config');
+    $this->assertInstanceOf('\Drupal\Core\Config\Config', $result);
+    $this->assertNotInstanceOf('\Drupal\Core\Config\ImmutableConfig', $result);
+
+    // Ensure that configuration that is expected to be immutable is.
+    $result = $config_method->invoke($trait, 'immutable.config');
+    $this->assertInstanceOf('\Drupal\Core\Config\ImmutableConfig', $result);
+  }
+
+  /**
+   * @covers ::config
+   * @expectedException \LogicException
+   * @expectedExceptionMessage No config factory available for ConfigFormBaseTrait
+   */
+  public function testConfigFactoryException() {
+    $trait = $this->getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // There is no config factory available this should result in an exception.
+    $config_method->invoke($trait, 'editable.config');
+  }
+
+  /**
+   * @covers ::config
+   * @expectedException \LogicException
+   * @expectedExceptionMessage No config factory available for ConfigFormBaseTrait
+   */
+  public function testConfigFactoryExceptionInvalidProperty() {
+    $trait = $this->getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    $trait->configFactory = TRUE;
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // There is no config factory available this should result in an exception.
+    $config_method->invoke($trait, 'editable.config');
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
index ea37f39..3f60933 100644
--- a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
@@ -144,7 +144,7 @@ public function testSaveOverride() {
 
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValue($config));
 
     $static_override = new StaticMenuLinkOverrides($config_factory);
@@ -186,7 +186,7 @@ public function testDeleteOverrides($ids, array $old_definitions, array $new_def
 
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValue($config));
 
     $static_override = new StaticMenuLinkOverrides($config_factory);
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 1a0ac77..d6deb9e 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -100,13 +100,11 @@ protected function assertArrayEquals(array $expected, array $actual, $message =
    *   A MockBuilder object for the ConfigFactory with the desired return values.
    */
   public function getConfigFactoryStub(array $configs = array()) {
-    $config_map = array();
+    $config_get_map = array();
+    $config_editable_map = array();
     // Construct the desired configuration object stubs, each with its own
     // desired return map.
     foreach ($configs as $config_name => $config_values) {
-      $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
-        ->disableOriginalConstructor()
-        ->getMock();
       $map = array();
       foreach ($config_values as $key => $value) {
         $map[] = array($key, $value);
@@ -114,18 +112,31 @@ public function getConfigFactoryStub(array $configs = array()) {
       // Also allow to pass in no argument.
       $map[] = array('', $config_values);
 
-      $config_object->expects($this->any())
+      $immutable_config_object = $this->getMockBuilder('Drupal\Core\Config\ImmutableConfig')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $immutable_config_object->expects($this->any())
         ->method('get')
         ->will($this->returnValueMap($map));
+      $config_get_map[] = array($config_name, $immutable_config_object);
 
-      $config_map[] = array($config_name, $config_object);
+      $mutable_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $mutable_config_object->expects($this->any())
+        ->method('get')
+        ->will($this->returnValueMap($map));
+      $config_editable_map[] = array($config_name, $mutable_config_object);
     }
     // Construct a config factory with the array of configuration object stubs
     // as its return map.
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->any())
       ->method('get')
-      ->will($this->returnValueMap($config_map));
+      ->will($this->returnValueMap($config_get_map));
+    $config_factory->expects($this->any())
+      ->method('getEditable')
+      ->will($this->returnValueMap($config_editable_map));
     return $config_factory;
   }
 
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 53d31d9..1ca1110 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -586,7 +586,18 @@
  * the default settings.php.
  *
  * Note that any values you provide in these variable overrides will not be
- * modifiable from the Drupal administration interface.
+ * viewable from the Drupal administration interface. The administration
+ * interface displays the values stored in configuration so that you can stage
+ * changes to other environments that don't have the overrides.
+ *
+ * There are particular configuration values that are risky to override. For
+ * example, overriding the list of installed modules in 'core.extension' is not
+ * supported as module install or uninstall has not occurred. Other examples
+ * include field storage configuration, because it has effects on database
+ * structure, and 'core.menu.static_menu_link_overrides' since this is cached in
+ * a way that is not config override aware. Also, note that changing
+ * configuration values in settings.php will not fire any of the configuration
+ * change events.
  */
 # $config['system.site']['name'] = 'My Drupal site';
 # $config['system.theme']['default'] = 'stark';