diff --git a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
index 0fad28c..3659dee 100644
--- a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
+++ b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
@@ -52,6 +52,17 @@ public function getEntityTypeId();
    *   "tags" "is the same as "tags.value" as value is the default column.
    *   If two or more conditions have the same field names they apply to the
    *   same delta within that field.
+   *   It is also possible to add the numeric delta value between the field
+   *   name and the column name, for example tags.5.value.
+   *   Finally, it's possible to create a condition on delta itself by using a
+   *   ? as a wildcard. For example, ->condition('tags.?', 5) will find only
+   *   entities which have at least six tags. Also, tags.? within a condition
+   *   group means a specific delta so
+   * @code
+   *   ->condition('tags.?', 0, '>'))
+   *   ->condition('tags.?.value', 'foo'))
+   * @endcode
+   *   will only find the "foo" tag if it is not the first tag.
    * @param $value
    *   The value for $field. In most cases, this is a scalar and it's treated as
    *   case-insensitive. For more complex operators, it is an array. The meaning
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index 65885e0..2277900 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -116,11 +116,35 @@ public function addField($field, $type, $langcode) {
 
       // Check whether this field is stored in a dedicated table.
       if ($field_storage && $table_mapping->requiresDedicatedTableStorage($field_storage)) {
+        $delta = NULL;
         // Find the field column.
         $column = $field_storage->getMainPropertyName();
 
         if ($key < $count) {
           $next = $specifiers[$key + 1];
+          // Is this a delta value?
+          if (is_numeric($next)) {
+            $delta = $next;
+            $index_prefix .= ".$delta";
+            // Do not process it again.
+            $key++;
+            $next = $specifiers[$key + 1];
+          }
+          // Is this a delta wildcard?
+          elseif ($next == '?') {
+            $index_prefix .= '.?';
+            // Do not process it again.
+            $key++;
+            // If there are yet specifiers to work with then continue
+            // processing. If this is the last specifier then use the delta
+            // wildcard as column name.
+            if ($key < $count) {
+              $next = $specifiers[$key + 1];
+            }
+            else {
+              $column = '_delta';
+            }
+          }
           // Is this a field column?
           $columns = $field_storage->getColumns();
           if (isset($columns[$next]) || in_array($next, $table_mapping->getReservedColumns())) {
@@ -144,7 +168,7 @@ public function addField($field, $type, $langcode) {
             $next_index_prefix = "$relationship_specifier.$column";
           }
         }
-        $table = $this->ensureFieldTable($index_prefix, $field_storage, $type, $langcode, $base_table, $entity_id_field, $field_id_field);
+        $table = $this->ensureFieldTable($index_prefix, $field_storage, $type, $langcode, $base_table, $entity_id_field, $field_id_field, $delta);
         $sql_column = $table_mapping->getFieldColumnName($field_storage, $column);
         $property_definitions = $field_storage->getPropertyDefinitions();
         if (isset($property_definitions[$column])) {
@@ -244,7 +268,7 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode,
    * @return string
    * @throws \Drupal\Core\Entity\Query\QueryException
    */
-  protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) {
+  protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field, $delta) {
     $field_name = $field->getName();
     if (!isset($this->fieldTables[$index_prefix . $field_name])) {
       $entity_type_id = $this->sqlQuery->getMetaData('entity_type');
@@ -254,12 +278,12 @@ protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $b
       if ($field->getCardinality() != 1) {
         $this->sqlQuery->addMetaData('simple_query', FALSE);
       }
-      $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field", $langcode);
+      $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field", $langcode, $delta);
     }
     return $this->fieldTables[$index_prefix . $field_name];
   }
 
-  protected function addJoin($type, $table, $join_condition, $langcode) {
+  protected function addJoin($type, $table, $join_condition, $langcode, $delta = NULL) {
     $arguments = array();
     if ($langcode) {
       $entity_type_id = $this->sqlQuery->getMetaData('entity_type');
@@ -271,6 +295,11 @@ protected function addJoin($type, $table, $join_condition, $langcode) {
       $join_condition .= ' AND %alias.' . $langcode_key . ' = ' . $placeholder;
       $arguments[$placeholder] = $langcode;
     }
+    if (isset($delta)) {
+      $placeholder = ':delta' . $this->sqlQuery->nextPlaceholder();
+      $join_condition .= ' AND %alias.delta = ' . $placeholder;
+      $arguments[$placeholder] = $delta;
+    }
     return $this->sqlQuery->addJoin($type, $table, NULL, $join_condition, $arguments);
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php b/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php
index 0301396..3f0270f 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php
@@ -16,8 +16,10 @@
    * Adds a field to a database query.
    *
    * @param string $field
-   *   If it contains a dot, then field name dot field column. If it doesn't
-   *   then entity property name.
+   *   If it doesn't contain a dot, then an entity base field name.
+   *   If it contains a dot, then either field name dot field column or
+   *   field name dot delta dot field column. Delta can be a numeric value or a
+   *   ? for any value.
    * @param string $type
    *   Join type, can either be INNER or LEFT.
    * @param string $langcode
diff --git a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
index c63ca4d..d8377d5 100644
--- a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
+++ b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
@@ -150,7 +150,12 @@ public function getFieldColumnName(FieldStorageDefinitionInterface $storage_defi
       $column_name = count($storage_definition->getColumns()) == 1 ? $field_name :  $field_name . '__' . $property_name;
     }
     elseif ($this->requiresDedicatedTableStorage($storage_definition)) {
-      $column_name = !in_array($property_name, $this->getReservedColumns()) ? $field_name . '_' . $property_name : $property_name;
+      if ($property_name == '_delta') {
+        $column_name = 'delta';
+      }
+      else {
+        $column_name = !in_array($property_name, $this->getReservedColumns()) ? $field_name . '_' . $property_name : $property_name;
+      }
     }
     else {
       throw new SqlContentEntityStorageException(String::format('Column information not available for the "@field_name" field.', array('@field_name' => $field_name)));
diff --git a/core/modules/system/src/Tests/Entity/EntityQueryTest.php b/core/modules/system/src/Tests/Entity/EntityQueryTest.php
index 2620b42..1b504c5 100644
--- a/core/modules/system/src/Tests/Entity/EntityQueryTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityQueryTest.php
@@ -445,6 +445,44 @@ public function testCount() {
      $this->assertFalse($count);
   }
 
+  /**
+   * Test queries with delta conditions.
+   */
+  public function testDelta() {
+    $figures = $this->figures;
+    // Test numeric delta value in field condition.
+    $this->queryResults = $this->factory->get('entity_test_mulrev')
+      ->condition("$figures.0.color", 'red')
+      ->sort('id')
+      ->execute();
+    // As unit 0 at delta 0 was the red triangle bit 0 needs to be set.
+    $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
+
+    $this->queryResults = $this->factory->get('entity_test_mulrev')
+      ->condition("$figures.1.color", 'red')
+      ->sort('id')
+      ->execute();
+    // Delta 1 is not red.
+    $this->assertResult();
+
+    // Test '?' wildcard
+    $this->queryResults = $this->factory->get('entity_test_mulrev')
+      ->condition("$figures.?.color", array('blue', 'red'))
+      ->condition("$figures.?", array(0, 1), 'IN')
+      ->sort('id')
+      ->execute();
+    // Figure delta 0 or 1 can be blue or red, this matches a lot of entities.
+    $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
+
+    // Test '?' wildcard without other conditions.
+    $this->queryResults = $this->factory->get('entity_test_mulrev')
+      ->condition("$figures.?", 1)
+      ->sort('id')
+      ->execute();
+    // Entity needs to have atleast two figures.
+    $this->assertResult(3, 7, 11, 15);
+  }
+
   protected function assertResult() {
     $assert = array();
     $expected = func_get_args();
