diff --git a/README.txt b/README.txt
index d4815fa..2919fd4 100644
--- a/README.txt
+++ b/README.txt
@@ -9,6 +9,23 @@ To set a site in read-only mode add this to setting.php:
 
     $settings['config_readonly'] = TRUE;
 
+To provide a whitelist of configuration that can be changed when in read-only
+mode add this to settings.php:
+
+    $settings['config_readonly_whitelist_patterns'] = [
+      'config_name.to.ignore',
+      'wildcards*allowed',
+    ];
+
+Or implement the hook:
+
+    hook_config_readonly_whitelist_patterns() {
+      return [
+        'config_name.to.ignore',
+        'wildcards*allowed',
+      ];
+    }
+
 To lock production and not other environments, your code in settings.php
 might be a conditional on an environment variable like:
 
diff --git a/config_readonly.module b/config_readonly.module
index b8d8cb7..1e00f43 100644
--- a/config_readonly.module
+++ b/config_readonly.module
@@ -35,3 +35,10 @@ function config_readonly_form_alter(array &$form, FormStateInterface &$form_stat
 function _config_readonly_validate_failure(array $form, FormStateInterface &$form_state) {
   $form_state->setErrorByName(NULL, t('This configuration form cannot be saved because the configuration active store is read-only.'));
 }
+
+/**
+ * Implements hook_config_readonly_whitelist_patterns().
+ */
+function config_readonly_config_readonly_whitelist_patterns() {
+  return Settings::get('config_readonly_whitelist_patterns');
+}
diff --git a/config_readonly.services.yml b/config_readonly.services.yml
index 8d15c34..9de5ca3 100644
--- a/config_readonly.services.yml
+++ b/config_readonly.services.yml
@@ -1,5 +1,6 @@
 services:
   config_readonly_form_subscriber:
     class: Drupal\config_readonly\EventSubscriber\ReadOnlyFormSubscriber
+    arguments: ['@module_handler']
     tags:
       - { name: event_subscriber }
diff --git a/src/Config/ConfigReadonlyStorage.php b/src/Config/ConfigReadonlyStorage.php
index f36c35a..eebba14 100644
--- a/src/Config/ConfigReadonlyStorage.php
+++ b/src/Config/ConfigReadonlyStorage.php
@@ -2,12 +2,15 @@
 
 namespace Drupal\config_readonly\Config;
 
+use Drupal\config_readonly\Exception\ConfigReadonlyStorageException;
 use Drupal\Core\Config\CachedStorage;
 use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\Core\Site\Settings;
+use Drupal\config_readonly\ConfigReadonlyWhitelistTrait;
 
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -17,6 +20,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
  * operations.
  */
 class ConfigReadonlyStorage extends CachedStorage {
+  use ConfigReadonlyWhitelistTrait;
 
   /**
    * The used lock backend instance.
@@ -43,11 +47,14 @@ class ConfigReadonlyStorage extends CachedStorage {
    *   The lock backend to check if config imports are in progress.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks.
    */
-  public function __construct(StorageInterface $storage, CacheBackendInterface $cache, LockBackendInterface $lock, RequestStack $request_stack) {
+  public function __construct(StorageInterface $storage, CacheBackendInterface $cache, LockBackendInterface $lock, RequestStack $request_stack, ModuleHandlerInterface $module_handler) {
     parent::__construct($storage, $cache);
     $this->lock = $lock;
     $this->requestStack = $request_stack;
+    $this->setModuleHandler($module_handler);
   }
 
   /**
@@ -58,51 +65,61 @@ class ConfigReadonlyStorage extends CachedStorage {
       $this->storage->createCollection($collection),
       $this->cache,
       $this->lock,
-      $this->requestStack
+      $this->requestStack,
+      $this->moduleHandler
     );
   }
 
   /**
    * {@inheritdoc}
    *
-   * @throws \Exception
+   * @throws \Drupal\config_readonly\Exception\ConfigReadonlyStorageException
    */
   public function write($name, array $data) {
-    $this->checkLock();
+    $this->checkLock($name);
     return parent::write($name, $data);
   }
 
   /**
    * {@inheritdoc}
    *
-   * @throws \Exception
+   * @throws \Drupal\config_readonly\Exception\ConfigReadonlyStorageException
    */
   public function delete($name) {
-    $this->checkLock();
+    $this->checkLock($name);
     return parent::delete($name);
   }
 
   /**
    * {@inheritdoc}
    *
-   * @throws Exception
+   * @throws \Drupal\config_readonly\Exception\ConfigReadonlyStorageException
    */
   public function rename($name, $new_name) {
-    $this->checkLock();
+    $this->checkLock($name);
+    $this->checkLock($new_name);
     return parent::rename($name, $new_name);
   }
 
   /**
    * {@inheritdoc}
    *
-   * @throws \Exception
+   * @throws \Drupal\config_readonly\Exception\ConfigReadonlyStorageException
    */
   public function deleteAll($prefix = '') {
     $this->checkLock();
     return parent::deleteAll($prefix);
   }
 
-  protected function checkLock() {
+  /**
+   * Check whether config is currently locked.
+   *
+   * @param string $name
+   *   Check for a specific lock config.
+   *
+   * @throws \Drupal\config_readonly\Exception\ConfigReadonlyStorageException
+   */
+  protected function checkLock($name = '') {
     // If settings.php says to lock config changes and if the config importer
     // isn't running (we do not want to lock config imports), then throw an
     // exception.
@@ -115,7 +132,13 @@ class ConfigReadonlyStorage extends CachedStorage {
         // @todo - always allow or support a flag for blocking it?
         return;
       }
-      throw new \Exception('Your site configuration active store is currently locked.');
+
+      // Don't block particular patterns.
+      if ($name && $this->matchesWhitelistPattern($name)) {
+        return;
+      }
+
+      throw new ConfigReadonlyStorageException('Your site configuration active store is currently locked.');
     }
   }
 
diff --git a/src/ConfigReadonlyServiceProvider.php b/src/ConfigReadonlyServiceProvider.php
index cb0d277..f5ad06c 100644
--- a/src/ConfigReadonlyServiceProvider.php
+++ b/src/ConfigReadonlyServiceProvider.php
@@ -30,8 +30,7 @@ class ConfigReadonlyServiceProvider implements ServiceProviderInterface, Service
     if ($container->getParameter('kernel.environment') !== 'install') {
       $definition = $container->getDefinition('config.storage');
       $definition->setClass('Drupal\config_readonly\Config\ConfigReadonlyStorage');
-      $definition->setArguments([new Reference('config.storage.active'), new Reference('cache.config'), new Reference('lock'), new Reference('request_stack')]);
+      $definition->setArguments([new Reference('config.storage.active'), new Reference('cache.config'), new Reference('lock'), new Reference('request_stack'), new Reference('module_handler')]);
     }
   }
 }
-
diff --git a/src/ConfigReadonlyWhitelistTrait.php b/src/ConfigReadonlyWhitelistTrait.php
new file mode 100644
index 0000000..3138de4
--- /dev/null
+++ b/src/ConfigReadonlyWhitelistTrait.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace Drupal\config_readonly;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+/**
+ * Trait ConfigReadonlyWhitelistTrait.
+ *
+ * @package Drupal\config_readonly
+ */
+trait ConfigReadonlyWhitelistTrait {
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * An array to store the whitelist ignore patterns.
+   *
+   * @var string[]
+   */
+  protected $patterns = [];
+
+  /**
+   * Set the module handler.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks.
+   */
+  public function setModuleHandler(ModuleHandlerInterface $module_handler) {
+    $this->moduleHandler = $module_handler;
+  }
+
+
+  /**
+   * Get whitelist patterns.
+   *
+   * @return string[]
+   *   The whitelist patterns.
+   */
+  public function getWhitelistPatterns() {
+    if (!$this->patterns) {
+      $this->patterns = $this->moduleHandler->invokeAll('config_readonly_whitelist_patterns');
+    }
+    return $this->patterns;
+  }
+
+  /**
+   * Check if the given name matches any whitelist pattern.
+   *
+   * @param string $name
+   *   The config name.
+   *
+   * @return bool
+   *   Whether or not there is a match.
+   */
+  public function matchesWhitelistPattern($name) {
+    // Check for matches.
+    $patterns = $this->getWhitelistPatterns();
+    if ($patterns) {
+      foreach ($patterns as $pattern) {
+        $escaped = str_replace('\*', '.*', preg_quote($pattern, '/'));
+        if (preg_match('/^' . $escaped . '$/', $name)) {
+          return TRUE;
+        }
+      }
+    }
+    return FALSE;
+  }
+
+}
diff --git a/src/EventSubscriber/ReadOnlyFormSubscriber.php b/src/EventSubscriber/ReadOnlyFormSubscriber.php
index be78fcc..3924e13 100644
--- a/src/EventSubscriber/ReadOnlyFormSubscriber.php
+++ b/src/EventSubscriber/ReadOnlyFormSubscriber.php
@@ -1,23 +1,31 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\config_readonly\EventSubscriber\ReadOnlyFormSubscriber.
- */
-
 namespace Drupal\config_readonly\EventSubscriber;
 
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Entity\EntityFormInterface;
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\config_readonly\ReadOnlyFormEvent;
+use Drupal\config_readonly\ConfigReadonlyWhitelistTrait;
 
 /**
  * Check if the given form should be read-only.
  */
 class ReadOnlyFormSubscriber implements EventSubscriberInterface {
+  use ConfigReadonlyWhitelistTrait;
+
+  /**
+   * ReadOnlyFormSubscriber constructor.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke hooks.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler) {
+    $this->setModuleHandler($module_handler);
+  }
 
   /**
    * Form ids to mark as read only.
@@ -41,20 +49,39 @@ class ReadOnlyFormSubscriber implements EventSubscriberInterface {
    */
   public function onFormAlter(ReadOnlyFormEvent $event) {
     // Check if the form is a ConfigFormBase or a ConfigEntityListBuilder.
-    $build_info = $event->getFormState()->getBuildInfo();
-    $form_object = $build_info['callback_object'];
+    $form_object = $event->getFormState()->getFormObject();
     $mark_form_read_only = $form_object instanceof ConfigFormBase || $form_object instanceof ConfigEntityListBuilder;
 
     if (!$mark_form_read_only) {
       $mark_form_read_only = in_array($form_object->getFormId(), $this->readOnlyFormIds);
     }
 
-    // Check if the form is an EntityFormInterface and entity is a config entity.
+    // Check if the form is an EntityFormInterface and entity is a config
+    // entity.
     if (!$mark_form_read_only && $form_object instanceof EntityFormInterface) {
       $entity = $form_object->getEntity();
       $mark_form_read_only = $entity instanceof ConfigEntityInterface;
     }
 
+    // Don't block particular patterns.
+    if ($mark_form_read_only && $form_object instanceof EntityFormInterface) {
+      $entity = $form_object->getEntity();
+      $name = $entity->getConfigDependencyName();
+      if ($this->matchesWhitelistPattern($name)) {
+        $mark_form_read_only = FALSE;
+      }
+    }
+
+    if ($mark_form_read_only && $form_object instanceof ConfigFormBase) {
+      // Get the editable configuration names.
+      $editable_config = $this->getEditableConfigNames($form_object);
+
+      // If all editable config is in the whitelist, do not block the form.
+      if ($editable_config == array_filter($editable_config, [$this, 'matchesWhitelistPattern'])) {
+        $mark_form_read_only = FALSE;
+      }
+    }
+
     // Temporary exception to allow search form to being used until this core
     // issue is solved: https://www.drupal.org/node/2845743.
     if ($mark_form_read_only && in_array($form_object->getFormId(), $this->formIdExceptions)) {
@@ -75,4 +102,25 @@ class ReadOnlyFormSubscriber implements EventSubscriberInterface {
     return $events;
   }
 
+  /**
+   * Get the editable configuration names.
+   *
+   * @param ConfigFormBase $form
+   *   The configuration form.
+   *
+   * @return array
+   *   An array of configuration object names that are editable if called in
+   *   conjunction with the trait's config() method.
+   *
+   * @see ConfigFormBaseTrait::getEditableConfigNames()
+   */
+  protected function getEditableConfigNames(ConfigFormBase $form) {
+    // Use reflection to work around getEditableConfigNames() as protected.
+    // @todo Review in 9.x for API change.
+    // @see https://www.drupal.org/node/2095289
+    $reflection = new \ReflectionMethod(get_class($form), 'getEditableConfigNames');
+    $reflection->setAccessible(TRUE);
+    return $reflection->invoke($form);
+  }
+
 }
diff --git a/src/Exception/ConfigReadonlyStorageException.php b/src/Exception/ConfigReadonlyStorageException.php
new file mode 100644
index 0000000..b87281a
--- /dev/null
+++ b/src/Exception/ConfigReadonlyStorageException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\config_readonly\Exception;
+
+/**
+ * Defines an exception thrown when attempting to save config that is locked.
+ */
+class ConfigReadonlyStorageException extends \RuntimeException {
+
+}
diff --git a/src/Tests/ReadOnlyConfigWhitelistTest.php b/src/Tests/ReadOnlyConfigWhitelistTest.php
new file mode 100644
index 0000000..850b3e7
--- /dev/null
+++ b/src/Tests/ReadOnlyConfigWhitelistTest.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Drupal\config_readonly\Tests;
+
+/**
+ * Tests read-only module config whitelist functionality.
+ *
+ * @group ConfigReadOnly
+ */
+class ReadOnlyConfigWhitelistTest extends ReadOnlyConfigTest {
+
+  public static $modules = [
+    'config',
+    'config_readonly',
+    'node',
+    'config_readonly_whitelist_test',
+  ];
+
+  /**
+   * Ensure that the whitelist allows a read-only form to become saveable.
+   */
+  public function testWhitelist() {
+    $this->createContentType([
+      'type' => 'article1',
+      'name' => 'Article1',
+    ]);
+    $this->createContentType([
+      'type' => 'article2',
+      'name' => 'Article2',
+    ]);
+
+    $this->turnOnReadOnlySetting();
+
+    $this->drupalGet('admin/structure/types/manage/article1');
+    $this->assertText('This form will not be saved because the configuration active store is read-only.', 'Warning shown on edit node type page.');
+
+    $this->drupalGet('admin/structure/types/manage/article2');
+    $this->assertNoText('This form will not be saved because the configuration active store is read-only.', 'Warning not show on edit node type page.');
+  }
+
+  /**
+   * Test simple config with whitelist.
+   */
+  public function testSimpleConfig() {
+    $this->drupalGet('admin/config/development/configuration/single/import');
+    $this->assertNoText('This form will not be saved because the configuration active store is read-only.', 'Warning not shown on single config import page.');
+
+    $this->drupalGet('admin/config/development/performance');
+    $this->assertNoText('This form will not be saved because the configuration active store is read-only.', 'Warning not shown on performance config page.');
+
+    $this->turnOnReadOnlySetting();
+    $this->drupalGet('admin/config/development/configuration/single/import');
+    $this->assertText('This form will not be saved because the configuration active store is read-only.', 'Warning shown on single config import page.');
+
+    $this->drupalGet('admin/config/development/performance');
+    $this->assertNoText('This form will not be saved because the configuration active store is read-only.', 'Warning not shown on performance config page.');
+  }
+
+}
diff --git a/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.info.yml b/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.info.yml
new file mode 100644
index 0000000..6b6a890
--- /dev/null
+++ b/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.info.yml
@@ -0,0 +1,8 @@
+name: 'Config Readonly Whitelist test'
+type: module
+description: 'Provides test whitelist.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - config_readonly
diff --git a/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.module b/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.module
new file mode 100644
index 0000000..49e5b2f
--- /dev/null
+++ b/tests/modules/config_readonly_whitelist_test/config_readonly_whitelist_test.module
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Provide test whitelist.
+ */
+
+/**
+ * Implements hook_config_readonly_whitelist_patterns().
+ */
+function config_readonly_whitelist_test_config_readonly_whitelist_patterns() {
+  return [
+    '*article2*',
+    'system.performance',
+  ];
+}
