diff --git a/core/core.services.yml b/core/core.services.yml
index 5959c44..4f204b5 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -719,7 +719,9 @@ services:
       - [setContainer, ['@service_container']]
   entity.query.config:
     class: Drupal\Core\Config\Entity\Query\QueryFactory
-    arguments: ['@config.factory']
+    arguments: ['@config.factory', '@keyvalue', '@config.manager']
+    tags:
+      - { name: event_subscriber }
   entity.query.sql:
     class: Drupal\Core\Entity\Query\Sql\QueryFactory
     arguments: ['@database']
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
index ddba9f1..b559d19 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
@@ -61,6 +61,8 @@ class ConfigEntityType extends EntityType {
    */
   protected $static_cache = FALSE;
 
+  protected $lookups = [];
+
   /**
    * {@inheritdoc}
    *
@@ -85,6 +87,7 @@ public function __construct($definition) {
     $this->handlers += array(
       'storage' => 'Drupal\Core\Config\Entity\ConfigEntityStorage',
     );
+    $this->lookups['uuid'] = 'UNIQUE';
   }
 
   /**
@@ -173,4 +176,12 @@ protected function checkStorageClass($class) {
     }
   }
 
+  public function getLookups() {
+    return $this->lookups;
+  }
+
+  public function getLookupType($lookup) {
+    return isset($this->lookups[$lookup]) ? $this->lookups[$lookup] : FALSE;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Entity/Query/Query.php b/core/lib/Drupal/Core/Config/Entity/Query/Query.php
index 2ad4db5..a5a70d0 100644
--- a/core/lib/Drupal/Core/Config/Entity/Query/Query.php
+++ b/core/lib/Drupal/Core/Config/Entity/Query/Query.php
@@ -11,6 +11,8 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryBase;
 use Drupal\Core\Entity\Query\QueryInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
 
 /**
  * Defines the entity query for configuration entities.
@@ -25,6 +27,11 @@ class Query extends QueryBase implements QueryInterface {
   protected $configFactory;
 
   /**
+   * The config key store.
+   */
+  protected $configKeyStore;
+
+  /**
    * Constructs a Query object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -34,12 +41,16 @@ class Query extends QueryBase implements QueryInterface {
    *   - OR: at least one of the conditions on the query need to match.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory.
+   * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value
+   *   The key value store used to store denormalized configuration entity key
+   *   data.
    * @param array $namespaces
    *   List of potential namespaces of the classes belonging to this query.
    */
-  function __construct(EntityTypeInterface $entity_type, $conjunction, ConfigFactoryInterface $config_factory, array $namespaces) {
+  function __construct(EntityTypeInterface $entity_type, $conjunction, ConfigFactoryInterface $config_factory, KeyValueStoreInterface $key_value, array $namespaces) {
     parent::__construct($entity_type, $conjunction, $namespaces);
     $this->configFactory = $config_factory;
+    $this->configKeyStore = $key_value;
   }
 
   /**
@@ -108,37 +119,50 @@ protected function loadRecords() {
     $prefix = $this->entityType->getConfigPrefix() . '.';
     $prefix_length = strlen($prefix);
 
-    // Search the conditions for restrictions on entity IDs.
-    $ids = array();
+    // Search the conditions for restrictions on configuration object names.
+    $names = FALSE;
     if ($this->condition->getConjunction() == 'AND') {
       foreach ($this->condition->conditions() as $condition) {
-        if (is_string($condition['field']) && $condition['field'] == $this->entityType->getKey('id')) {
-          $operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '=');
-          if ($operator == '=') {
-            $ids = array($condition['value']);
+        $operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '=');
+        if (is_string($condition['field']) && ($operator == 'IN' || $operator == '=')) {
+          // Special case ID lookups.
+          if ($condition['field'] == $this->entityType->getKey('id')) {
+            $ids = (array) $condition['value'];
+            $names = array_map(function ($id) use ($prefix) {
+              return $prefix . $id;
+            }, $ids);
           }
-          elseif ($operator == 'IN') {
-            $ids = $condition['value'];
-          }
-          // We stop at the first restricting condition on ID. In the (weird)
-          // case where there are additional restricting conditions, results
-          // will be eliminated when the conditions are checked on the loaded
-          // records.
-          if ($ids) {
-            break;
+          if ($lookup_type = $this->entityType->getLookupType($condition['field'])) {
+            $keys = (array) $condition['value'];
+            $keys = array_map(function ($value) use ($condition) {
+              return $condition['field'] . ':' . $value;
+            }, $keys);
+            if ($lookup_type == 'UNIQUE') {
+              $names = array_values($this->configKeyStore->getMultiple($keys));
+            }
+            else if ($lookup_type == 'NOT UNIQUE') {
+              foreach ($this->configKeyStore->getMultiple($keys) as $list) {
+                if (is_array($names)) {
+                  $names = array_merge($names, $list);
+                }
+                else {
+                  $names = $list;
+                }
+              }
+            }
           }
         }
+        // We stop at the first restricting condition on name. In the (weird)
+        // case where there are additional restricting conditions, results
+        // will be eliminated when the conditions are checked on the loaded
+        // records.
+        if ($names) {
+          break;
+        }
       }
     }
-    // If there are conditions restricting config ID, we can narrow the list of
-    // records to load and parse.
-    if ($ids) {
-      $names = array_map(function ($id) use ($prefix) {
-        return $prefix . $id;
-      }, $ids);
-    }
     // If no restrictions on IDs were found, we need to parse all records.
-    else {
+    if ($names === FALSE) {
       $names = $this->configFactory->listAll($prefix);
     }
 
diff --git a/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php b/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php
index 78d38f9..8dbe0ae 100644
--- a/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php
+++ b/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php
@@ -7,17 +7,22 @@
 
 namespace Drupal\Core\Config\Entity\Query;
 
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigCrudEvent;
+use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryBase;
 use Drupal\Core\Entity\Query\QueryException;
 use Drupal\Core\Entity\Query\QueryFactoryInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
  * Provides a factory for creating entity query objects for the config backend.
  */
-class QueryFactory implements QueryFactoryInterface {
+class QueryFactory implements QueryFactoryInterface, EventSubscriberInterface {
 
   /**
    * The config factory used by the config entity query.
@@ -36,13 +41,15 @@ class QueryFactory implements QueryFactoryInterface {
   /**
    * Constructs a QueryFactory object.
    *
-   * @param \Drupal\Core\Config\StorageInterface $config_storage
-   *   The config storage used by the config entity query.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config storage used by the config entity query.
+   * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value
+   *   The key value factory.
    */
-  public function __construct(ConfigFactoryInterface $config_factory) {
+  public function __construct(ConfigFactoryInterface $config_factory, KeyValueFactoryInterface $key_value, ConfigManagerInterface $config_manager) {
     $this->configFactory = $config_factory;
+    $this->keyValueFactory = $key_value;
+    $this->configManager = $config_manager;
     $this->namespaces = QueryBase::getNamespaces($this);
   }
 
@@ -50,7 +57,7 @@ public function __construct(ConfigFactoryInterface $config_factory) {
    * {@inheritdoc}
    */
   public function get(EntityTypeInterface $entity_type, $conjunction) {
-    return new Query($entity_type, $conjunction, $this->configFactory, $this->namespaces);
+    return new Query($entity_type, $conjunction, $this->configFactory, $this->getKeyValueStore($entity_type), $this->namespaces);
   }
 
   /**
@@ -60,4 +67,137 @@ public function getAggregate(EntityTypeInterface $entity_type, $conjunction) {
       throw new QueryException('Aggregation over configuration entities is not supported');
   }
 
+  /**
+   * Gets the key value store where denormalized data is stored.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   *   The key value store where denormalized data is stored.
+   */
+  protected function getKeyValueStore(EntityTypeInterface $entity_type) {
+    return $this->keyValueFactory->get('config.entity.key_store.' . $entity_type->id());
+  }
+
+  /**
+   * Updates or adds denormalized data.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   * @param \Drupal\Core\Config\Config $config
+   *   The configuration object that is being saved.
+   */
+  protected function updateConfigKeyStore(EntityTypeInterface $entity_type, Config $config) {
+    $config_key_store = $this->getKeyValueStore($entity_type);
+    foreach ($entity_type->getLookups() as $lookup_key => $type) {
+      foreach($this->getKeys($lookup_key, $config) as $key) {
+        if ($type == 'UNIQUE') {
+          $config_key_store->set($key, $config->getName());
+        }
+        else {
+          if ($type == 'NOT UNIQUE') {
+            $values = $config_key_store->get($key, []);
+            if (!in_array($config->getName(), $values, TRUE)) {
+              $values[] = $config->getName();
+              $config_key_store->set($key, $values);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes denormalized data.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   * @param \Drupal\Core\Config\Config $config
+   *   The configuration object that is being deleted.
+   */
+  protected function deleteConfigKeyStore(EntityTypeInterface $entity_type, Config $config) {
+    $config_key_store = $this->getKeyValueStore($entity_type);
+    foreach ($entity_type->getLookups() as $lookup_key => $type) {
+      foreach($this->getKeys($lookup_key, $config, 'getOriginal') as $key) {
+        if ($type == 'UNIQUE') {
+          $config_key_store->delete($key);
+        }
+        else {
+          if ($type == 'NOT UNIQUE') {
+            $values = $config_key_store->get($key, []);
+            if ($pos = array_search($config->getName(), $values, TRUE)) {
+              unset($values[$pos]);
+            }
+            if (empty($values)) {
+              $config_key_store->delete($key);
+            }
+            else {
+              $config_key_store->set($key, $values);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  protected function getKeys($key, Config $config, $get_method = 'get') {
+    $parts = explode('.*.', $key);
+    $values = (array) $this->getValues($config, $parts, $parts[0], $get_method);
+    return array_map(function($value) use ($key) { return $key . ':' . $value; }, $values);
+  }
+
+  protected function getValues(Config $config, $parts, $key, $get_method = 'get', $start = 0) {
+    $value = $config->$get_method($key);
+    if (is_array($value)) {
+      $new_value = [];
+      $start++;
+      foreach (array_keys($value) as $key_bit) {
+        $new_key = $key . '.' . $key_bit . '.' . $parts[$start];
+        $new_value[] = $this->getValues($config, $parts, $new_key, $get_method, $start);
+      }
+      $value = $new_value;
+    }
+    return $value;
+  }
+
+  /**
+   * Updates configuration entity in the key store.
+   *
+   * @param ConfigCrudEvent $event
+   *   The configuration event.
+   */
+  public function onConfigSave(ConfigCrudEvent $event) {
+    $saved_config = $event->getConfig();
+    $entity_type_id = $this->configManager->getEntityTypeIdByName($saved_config->getName());
+    if ($entity_type_id) {
+      $entity_type = $this->configManager->getEntityManager()->getDefinition($entity_type_id);
+      $this->updateConfigKeyStore($entity_type, $saved_config);
+    }
+  }
+
+  /**
+   * Removes configuration entity from key store.
+   *
+   * @param \Drupal\Core\Config\ConfigCrudEvent $event
+   *   The configuration event.
+   */
+  public function onConfigDelete(ConfigCrudEvent $event) {
+    $saved_config = $event->getConfig();
+    $entity_type_id = $this->configManager->getEntityTypeIdByName($saved_config->getName());
+    if ($entity_type_id) {
+      $entity_type = $this->configManager->getEntityManager()->getDefinition($entity_type_id);
+      $this->deleteConfigKeyStore($entity_type, $saved_config);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ConfigEvents::SAVE][] = array('onConfigSave', 128);
+    $events[ConfigEvents::DELETE][] = array('onConfigDelete', 128);
+    return $events;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Field/BaseFieldOverrideStorage.php b/core/lib/Drupal/Core/Field/BaseFieldOverrideStorage.php
index 0b559ba..04939d8 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldOverrideStorage.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldOverrideStorage.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field;
 
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -32,8 +33,8 @@ class BaseFieldOverrideStorage extends FieldConfigStorageBase {
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
    *   The field type plugin manager.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value, FieldTypePluginManagerInterface $field_type_manager) {
+    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $key_value);
     $this->fieldTypeManager = $field_type_manager;
   }
 
@@ -46,6 +47,7 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('uuid'),
       $container->get('language_manager'),
+      $container->get('keyvalue'),
       $container->get('plugin.manager.field.field_type')
     );
   }
diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php
index 4af2f80..40e9fea 100644
--- a/core/modules/block/src/Entity/Block.php
+++ b/core/modules/block/src/Entity/Block.php
@@ -38,6 +38,9 @@
  *   links = {
  *     "delete-form" = "/admin/structure/block/manage/{block}/delete",
  *     "edit-form" = "/admin/structure/block/manage/{block}"
+ *   },
+ *   lookups = {
+ *     "theme" = "NOT UNIQUE"
  *   }
  * )
  */
diff --git a/core/modules/field/src/FieldConfigStorage.php b/core/modules/field/src/FieldConfigStorage.php
index 89ea181..cfa10ca 100644
--- a/core/modules/field/src/FieldConfigStorage.php
+++ b/core/modules/field/src/FieldConfigStorage.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldConfigStorageBase;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -62,8 +63,8 @@ class FieldConfigStorage extends FieldConfigStorageBase {
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
    *   The field type plugin manager.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, StateInterface $state, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value, EntityManagerInterface $entity_manager, StateInterface $state, FieldTypePluginManagerInterface $field_type_manager) {
+    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $key_value);
     $this->entityManager = $entity_manager;
     $this->state = $state;
     $this->fieldTypeManager = $field_type_manager;
@@ -78,6 +79,7 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('uuid'),
       $container->get('language_manager'),
+      $container->get('keyvalue'),
       $container->get('entity.manager'),
       $container->get('state'),
       $container->get('plugin.manager.field.field_type')
diff --git a/core/modules/field/src/FieldStorageConfigStorage.php b/core/modules/field/src/FieldStorageConfigStorage.php
index 55800b3..4673f4a 100644
--- a/core/modules/field/src/FieldStorageConfigStorage.php
+++ b/core/modules/field/src/FieldStorageConfigStorage.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -72,8 +73,8 @@ class FieldStorageConfigStorage extends ConfigEntityStorage {
    * @param \Drupal\Component\Plugin\PluginManagerInterface\FieldTypePluginManagerInterface
    *   The field type plugin manager.
    */
-  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
+  public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value, EntityManagerInterface $entity_manager, ModuleHandler $module_handler, StateInterface $state, FieldTypePluginManagerInterface $field_type_manager) {
+    parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $key_value);
     $this->entityManager = $entity_manager;
     $this->moduleHandler = $module_handler;
     $this->state = $state;
@@ -89,6 +90,7 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('uuid'),
       $container->get('language_manager'),
+      $container->get('keyvalue'),
       $container->get('entity.manager'),
       $container->get('module_handler'),
       $container->get('state'),
diff --git a/core/modules/shortcut/src/ShortcutSetStorage.php b/core/modules/shortcut/src/ShortcutSetStorage.php
index f575856..08e6d98 100644
--- a/core/modules/shortcut/src/ShortcutSetStorage.php
+++ b/core/modules/shortcut/src/ShortcutSetStorage.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityStorage;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -44,8 +45,8 @@ class ShortcutSetStorage extends ConfigEntityStorage implements ShortcutSetStora
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
    */
-  public function __construct(EntityTypeInterface $entity_info, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager) {
-    parent::__construct($entity_info, $config_factory, $uuid_service, $language_manager);
+  public function __construct(EntityTypeInterface $entity_info, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value) {
+    parent::__construct($entity_info, $config_factory, $uuid_service, $language_manager, $key_value);
 
     $this->moduleHandler = $module_handler;
   }
@@ -59,7 +60,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('config.factory'),
       $container->get('uuid'),
       $container->get('module_handler'),
-      $container->get('language_manager')
+      $container->get('language_manager'),
+      $container->get('keyvalue')
     );
   }
 
diff --git a/core/modules/tour/src/Entity/Tour.php b/core/modules/tour/src/Entity/Tour.php
index d50caa9..6b6817f 100644
--- a/core/modules/tour/src/Entity/Tour.php
+++ b/core/modules/tour/src/Entity/Tour.php
@@ -24,6 +24,9 @@
  *   entity_keys = {
  *     "id" = "id",
  *     "label" = "label"
+ *   },
+ *   lookups = {
+ *     "routes.*.route_name" = "NOT UNIQUE"
  *   }
  * )
  */
