diff --git a/core/includes/database.inc b/core/includes/database.inc
index 44863df74f7b6eb77523df8dd67401fc85654fc3..ef94fddfb1458fe6a09d8150095446828a6bfd36 100644
--- a/core/includes/database.inc
+++ b/core/includes/database.inc
@@ -246,7 +246,9 @@
  * @param $query
  *   The prepared statement query to run. Although it will accept both named and
  *   unnamed placeholders, named placeholders are strongly preferred as they are
- *   more self-documenting.
+ *   more self-documenting. If the argument corresponding to a placeholder is
+ *   an array of values to be expanded, e.g. for an IN query, the placeholder
+ *   should be named with a trailing bracket like :example[]
  * @param $args
  *   An array of values to substitute into the query. If the query uses named
  *   placeholders, this is an associative array in any order. If the query uses
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index cc08cc5894ae6ca9271a734e138e7994a7a7fec3..87b54b181c4e27825f9a9f29ae68cda5f28385e0 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -86,7 +86,7 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     // ::select() is a much smaller proportion of the request.
     $result = array();
     try {
-      $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => array_keys($cid_mapping)));
+      $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN ( :cids[] )', array(':cids[]' => array_keys($cid_mapping)));
     }
     catch (\Exception $e) {
       // Nothing to do.
diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php
index cbfab041c40b255ed46cb67a600982b2ee493c90..b6d9161b4e4905e8ecb4a88191708e834b5f6df8 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php
@@ -108,7 +108,7 @@ public function calculateChecksum(array $tags) {
     if ($query_tags) {
       $db_tags = array();
       try {
-        $db_tags = $this->connection->query('SELECT tag, invalidations FROM {cachetags} WHERE tag IN (:tags)', array(':tags' => $query_tags))
+        $db_tags = $this->connection->query('SELECT tag, invalidations FROM {cachetags} WHERE tag IN ( :tags[] )', array(':tags[]' => $query_tags))
           ->fetchAllKeyed();
         $this->tagCache += $db_tags;
       }
diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php
index 471590ad64f1dc694e4e57a3b9ddd148112291f4..7a45969ee8c40e5aa16cde5bc839ef73fcf896ea 100644
--- a/core/lib/Drupal/Core/Config/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php
@@ -107,7 +107,7 @@ public function read($name) {
   public function readMultiple(array $names) {
     $list = array();
     try {
-      $list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN (:names)', array(':collection' => $this->collection, ':names' => $names), $this->options)->fetchAllKeyed();
+      $list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN ( :names[] )', array(':collection' => $this->collection, ':names[]' => $names), $this->options)->fetchAllKeyed();
       foreach ($list as &$data) {
         $data = $this->decode($data);
       }
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index e0c1714149bcb42292a55f25383460be0085c30b..935ef45e4a7c9c61c99868ca9653ddf0f32a2ae2 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -517,6 +517,7 @@ protected function filterComment($comment = '') {
    *
    * @throws \PDOException
    * @throws \Drupal\Core\Database\IntegrityConstraintViolationException
+   * @throws \InvalidArgumentException
    */
   public function query($query, array $args = array(), $options = array()) {
 
@@ -581,38 +582,48 @@ public function query($query, array $args = array(), $options = array()) {
    * Drupal supports an alternate syntax for doing arrays of values. We
    * therefore need to expand them out into a full, executable query string.
    *
-   * @param $query
+   * @param string $query
    *   The query string to modify.
-   * @param $args
+   * @param array $args
    *   The arguments for the query.
    *
-   * @return
+   * @return bool
    *   TRUE if the query was modified, FALSE otherwise.
    */
   protected function expandArguments(&$query, &$args) {
     $modified = FALSE;
 
-    // If the placeholder value to insert is an array, assume that we need
-    // to expand it out into a comma-delimited set of placeholders.
-    foreach (array_filter($args, 'is_array') as $key => $data) {
+    // If the placeholder indicated the value to use is an array,  we need to
+    // expand it out into a comma-delimited set of placeholders.
+    foreach ($args as $key => $data) {
+      $is_bracket_placeholder = substr($key, -2) === '[]';
+      $is_array_data = is_array($data);
+      if ($is_bracket_placeholder && !$is_array_data) {
+        throw new \InvalidArgumentException('Placeholders with a trailing [] can only be expanded with an array of values.');
+      }
+      elseif (!$is_bracket_placeholder) {
+        if ($is_array_data) {
+          throw new \InvalidArgumentException('Placeholders must have a trailing [] if they are to be expanded with an array of values.');
+        }
+        // Scalar placeholder - does not need to be expanded.
+        continue;
+      }
+      // Handle expansion of arrays.
+      $key_name = str_replace('[]', '__', $key);
       $new_keys = array();
+      // We require placeholders to have trailing brackets if the developer
+      // intends them to be expanded to an array to make the intent explicit.
       foreach (array_values($data) as $i => $value) {
         // This assumes that there are no other placeholders that use the same
-        // name.  For example, if the array placeholder is defined as :example
+        // name.  For example, if the array placeholder is defined as :example[]
         // and there is already an :example_2 placeholder, this will generate
         // a duplicate key.  We do not account for that as the calling code
         // is already broken if that happens.
-        $new_keys[$key . '_' . $i] = $value;
+        $new_keys[$key_name . $i] = $value;
       }
 
       // Update the query with the new placeholders.
-      // preg_replace is necessary to ensure the replacement does not affect
-      // placeholders that start with the same exact text. For example, if the
-      // query contains the placeholders :foo and :foobar, and :foo has an
-      // array of values, using str_replace would affect both placeholders,
-      // but using the following preg_replace would only affect :foo because
-      // it is followed by a non-word character.
-      $query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
+      $query = str_replace($key, implode(', ', array_keys($new_keys)), $query);
 
       // Update the args array with the new placeholders.
       unset($args[$key]);
diff --git a/core/lib/Drupal/Core/Database/Query/Condition.php b/core/lib/Drupal/Core/Database/Query/Condition.php
index 4dc70f31f3b7de5bd5df67eabfb5f5b9e8603abc..987fba85689c988a08385e5bee54d35ead93cf29 100644
--- a/core/lib/Drupal/Core/Database/Query/Condition.php
+++ b/core/lib/Drupal/Core/Database/Query/Condition.php
@@ -68,14 +68,9 @@ public function count() {
   /**
    * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
    */
-  public function condition($field, $value = NULL, $operator = NULL) {
-    if (!isset($operator)) {
-      if (is_array($value)) {
-        $operator = 'IN';
-      }
-      else {
-        $operator = '=';
-      }
+  public function condition($field, $value = NULL, $operator = '=') {
+    if (empty($operator)) {
+      $operator = '=';
     }
     if (empty($value) && is_array($value)) {
       throw new InvalidQueryException(sprintf("Query condition '%s %s ()' cannot be empty.", $field, $operator));
@@ -211,7 +206,7 @@ public function compile(Connection $connection, PlaceholderInterface $queryPlace
             // We assume that if there is a delimiter, then the value is an
             // array. If not, it is a scalar. For simplicity, we first convert
             // up to an array so that we can build the placeholders in the same way.
-            elseif (!$operator['delimiter']) {
+            elseif (!$operator['delimiter'] && !is_array($condition['value'])) {
               $condition['value'] = array($condition['value']);
             }
             if ($operator['use_value']) {
diff --git a/core/lib/Drupal/Core/Database/Query/ConditionInterface.php b/core/lib/Drupal/Core/Database/Query/ConditionInterface.php
index 4af00ab88e6628d3cbb04eff2b3a339754f5cc9c..923f35bf3e56621dd1785a960f45614692b28f26 100644
--- a/core/lib/Drupal/Core/Database/Query/ConditionInterface.php
+++ b/core/lib/Drupal/Core/Database/Query/ConditionInterface.php
@@ -46,8 +46,7 @@ interface ConditionInterface {
    *   the array is dependent on the $operator.
    * @param $operator
    *   The comparison operator, such as =, <, or >=. It also accepts more
-   *   complex options such as IN, LIKE, LIKE BINARY, or BETWEEN. Defaults to IN
-   *   if $value is an array, and = otherwise.
+   *   complex options such as IN, LIKE, LIKE BINARY, or BETWEEN. Defaults to =.
    *
    * @return \Drupal\Core\Database\Query\ConditionInterface
    *   The called object.
@@ -55,7 +54,7 @@ interface ConditionInterface {
    * @see \Drupal\Core\Database\Query\ConditionInterface::isNull()
    * @see \Drupal\Core\Database\Query\ConditionInterface::isNotNull()
    */
-  public function condition($field, $value = NULL, $operator = NULL);
+  public function condition($field, $value = NULL, $operator = '=');
 
   /**
    * Adds an arbitrary WHERE clause to the query.
diff --git a/core/lib/Drupal/Core/Database/Query/Delete.php b/core/lib/Drupal/Core/Database/Query/Delete.php
index 33727a724d9d6bcabf34aa7a6c98a256a8a5306d..88483917ff6c8c246c5aaa9eb113c81609b388b4 100644
--- a/core/lib/Drupal/Core/Database/Query/Delete.php
+++ b/core/lib/Drupal/Core/Database/Query/Delete.php
@@ -54,7 +54,7 @@ public function __construct(Connection $connection, $table, array $options = arr
   /**
    * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
    */
-  public function condition($field, $value = NULL, $operator = NULL) {
+  public function condition($field, $value = NULL, $operator = '=') {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Database/Query/Merge.php b/core/lib/Drupal/Core/Database/Query/Merge.php
index be71de3175540a492c1a1d9cb06f243d45756a21..b2ed83948eeda032a3b629b23f7b116f60e2d32e 100644
--- a/core/lib/Drupal/Core/Database/Query/Merge.php
+++ b/core/lib/Drupal/Core/Database/Query/Merge.php
@@ -342,7 +342,7 @@ public function key($field, $value = NULL) {
   /**
    * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
    */
-  public function condition($field, $value = NULL, $operator = NULL) {
+  public function condition($field, $value = NULL, $operator = '=') {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Database/Query/Select.php b/core/lib/Drupal/Core/Database/Query/Select.php
index 85b859bfe9c08a66f43eec8b5f821286b5b36868..70dc96f0183dcd2b579ed49d253a6f393ed3fc38 100644
--- a/core/lib/Drupal/Core/Database/Query/Select.php
+++ b/core/lib/Drupal/Core/Database/Query/Select.php
@@ -191,7 +191,7 @@ public function getMetaData($key) {
   /**
    * {@inheritdoc}
    */
-  public function condition($field, $value = NULL, $operator = NULL) {
+  public function condition($field, $value = NULL, $operator = '=') {
     $this->where->condition($field, $value, $operator);
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Database/Query/SelectExtender.php b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
index c4396d2f392ce670bd176c729895a4bc9943a602..f16838d3fb046bab79a2f0ec644fdc2467ce77e4 100644
--- a/core/lib/Drupal/Core/Database/Query/SelectExtender.php
+++ b/core/lib/Drupal/Core/Database/Query/SelectExtender.php
@@ -88,7 +88,7 @@ public function getMetaData($key) {
 
   /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */
 
-  public function condition($field, $value = NULL, $operator = NULL) {
+  public function condition($field, $value = NULL, $operator = '=') {
     $this->query->condition($field, $value, $operator);
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Database/Query/Update.php b/core/lib/Drupal/Core/Database/Query/Update.php
index ffbf6be53212e49f812fd3bdcdb275f6ebbd413f..4461ba082ccca0df3ad481ac873a95cb330d7a21 100644
--- a/core/lib/Drupal/Core/Database/Query/Update.php
+++ b/core/lib/Drupal/Core/Database/Query/Update.php
@@ -83,7 +83,7 @@ public function __construct(Connection $connection, $table, array $options = arr
   /**
    * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
    */
-  public function condition($field, $value = NULL, $operator = NULL) {
+  public function condition($field, $value = NULL, $operator = '=') {
     $this->condition->condition($field, $value, $operator);
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageBase.php b/core/lib/Drupal/Core/Entity/EntityStorageBase.php
index 7a43b75ad1b7ed8061691685b1ce3d062683ea8a..3528b7dd15f3c07f80f9d38cf0e4fb2c7ae83866 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageBase.php
@@ -454,7 +454,8 @@ abstract protected function doSave($id, EntityInterface $entity);
    */
   protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
     foreach ($values as $name => $value) {
-      $entity_query->condition($name, $value);
+      // Cast scalars to array so we can consistently use an IN condition.
+      $entity_query->condition($name, (array) $value, 'IN');
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
index ece96f5fc4fa15b5809bcbd013eeeacbce0dc9db..a3880f58d9b518dd8eb4d1c0f2de5402b6a2b97c 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -667,7 +667,7 @@ protected function attachPropertyData(array &$entities) {
       $table = $this->revisionDataTable ?: $this->dataTable;
       $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC))
         ->fields('data')
-        ->condition($this->idKey, array_keys($entities))
+        ->condition($this->idKey, array_keys($entities), 'IN')
         ->orderBy('data.' . $this->idKey);
 
       if ($this->revisionDataTable) {
@@ -676,7 +676,7 @@ protected function attachPropertyData(array &$entities) {
         foreach ($entities as $values) {
           $revision_ids[] = is_object($values) ? $values->getRevisionId() : $values[$this->revisionKey][LanguageInterface::LANGCODE_DEFAULT];
         }
-        $query->condition($this->revisionKey, $revision_ids);
+        $query->condition($this->revisionKey, $revision_ids, 'IN');
       }
 
       $data = $query->execute();
@@ -878,24 +878,24 @@ protected function doDelete($entities) {
     $ids = array_keys($entities);
 
     $this->database->delete($this->entityType->getBaseTable())
-      ->condition($this->idKey, $ids)
+      ->condition($this->idKey, $ids, 'IN')
       ->execute();
 
     if ($this->revisionTable) {
       $this->database->delete($this->revisionTable)
-        ->condition($this->idKey, $ids)
+        ->condition($this->idKey, $ids, 'IN')
         ->execute();
     }
 
     if ($this->dataTable) {
       $this->database->delete($this->dataTable)
-        ->condition($this->idKey, $ids)
+        ->condition($this->idKey, $ids, 'IN')
         ->execute();
     }
 
     if ($this->revisionDataTable) {
       $this->database->delete($this->revisionDataTable)
-        ->condition($this->idKey, $ids)
+        ->condition($this->idKey, $ids, 'IN')
         ->execute();
     }
 
diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
index e755832391c32eb89ed185838a670c9ceea49ac5..2014f4ad49a8b1aab3db64484a2fb4f7f8b5efb4 100644
--- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php
@@ -75,7 +75,7 @@ public function has($key) {
   public function getMultiple(array $keys) {
     $values = array();
     try {
-      $result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN (:keys) AND collection = :collection', array(':keys' => $keys, ':collection' => $this->collection))->fetchAllAssoc('name');
+      $result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN ( :keys[] ) AND collection = :collection', array(':keys[]' => $keys, ':collection' => $this->collection))->fetchAllAssoc('name');
       foreach ($keys as $key) {
         if (isset($result[$key])) {
           $values[$key] = $this->serializer->decode($result[$key]->value);
@@ -152,7 +152,7 @@ public function deleteMultiple(array $keys) {
     // Delete in chunks when a large array is passed.
     while ($keys) {
       $this->connection->delete($this->table)
-        ->condition('name', array_splice($keys, 0, 1000))
+        ->condition('name', array_splice($keys, 0, 1000), 'IN')
         ->condition('collection', $this->collection)
         ->execute();
     }
diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php
index 19dbb9922551f05a74ee2abb75669fecabb97f54..99e34c826a3aab6574737f36e2af5d06f9a68615 100644
--- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php
+++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php
@@ -51,10 +51,10 @@ public function has($key) {
    */
   public function getMultiple(array $keys) {
     $values = $this->connection->query(
-      'SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE expire > :now AND name IN (:keys) AND collection = :collection',
+      'SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE expire > :now AND name IN ( :keys[] ) AND collection = :collection',
       array(
         ':now' => REQUEST_TIME,
-        ':keys' => $keys,
+        ':keys[]' => $keys,
         ':collection' => $this->collection,
       ))->fetchAllKeyed();
     return array_map(array($this->serializer, 'decode'), $values);
diff --git a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
index 29fa9bcfb4ecc6f4ee4fbf51ff34b6fba4773427..d22f53888e007648584217550a8af85705f07368 100644
--- a/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
+++ b/core/lib/Drupal/Core/Menu/DefaultMenuLinkTreeManipulators.php
@@ -114,7 +114,7 @@ public function checkNodeAccess(array $tree) {
       $nids = array_keys($node_links);
 
       $query = $this->queryFactory->get('node');
-      $query->condition('nid', $nids);
+      $query->condition('nid', $nids, 'IN');
 
       // Allows admins to view all nodes, by both disabling node_access
       // query rewrite as well as not checking for the node status. The
diff --git a/core/lib/Drupal/Core/Path/AliasStorage.php b/core/lib/Drupal/Core/Path/AliasStorage.php
index 2719331f5dc3e5f31620ecf9e22c55d4f76b008f..bd027c8848ac6486b8a0a03931fd22f5bcb200bb 100644
--- a/core/lib/Drupal/Core/Path/AliasStorage.php
+++ b/core/lib/Drupal/Core/Path/AliasStorage.php
@@ -118,7 +118,7 @@ public function delete($conditions) {
    */
   public function preloadPathAlias($preloaded, $langcode) {
     $args = array(
-      ':system' => $preloaded,
+      ':system[]' => $preloaded,
       ':langcode' => $langcode,
       ':langcode_undetermined' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
     );
@@ -132,13 +132,13 @@ public function preloadPathAlias($preloaded, $langcode) {
     if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
       // Prevent PDO from complaining about a token the query doesn't use.
       unset($args[':langcode']);
-      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode = :langcode_undetermined ORDER BY pid ASC', $args);
+      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode = :langcode_undetermined ORDER BY pid ASC', $args);
     }
     elseif ($langcode < LanguageInterface::LANGCODE_NOT_SPECIFIED) {
-      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid ASC', $args);
+      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid ASC', $args);
     }
     else {
-      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args);
+      $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args);
     }
 
     return $result->fetchAllKeyed();
diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php
index da9dc1bcd83fbecf7b226c572330d172102bba87..26ff91d8f2dd49e1a1948f1823da403470bd3ab2 100644
--- a/core/lib/Drupal/Core/Routing/RouteProvider.php
+++ b/core/lib/Drupal/Core/Routing/RouteProvider.php
@@ -178,7 +178,7 @@ public function getRoutesByNames($names) {
 
     $routes_to_load = array_diff($names, array_keys($this->routes));
     if ($routes_to_load) {
-      $result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN (:names)', array(':names' => $routes_to_load));
+      $result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN ( :names[] )', array(':names[]' => $routes_to_load));
       $routes = $result->fetchAllKeyed();
 
       foreach ($routes as $name => $route) {
@@ -289,8 +289,8 @@ protected function getRoutesByPath($path) {
       return $collection;
     }
 
-    $routes = $this->connection->query("SELECT name, route FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN (:patterns) ORDER BY fit DESC, name ASC", array(
-      ':patterns' => $ancestors,
+    $routes = $this->connection->query("SELECT name, route FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN ( :patterns[] ) ORDER BY fit DESC, name ASC", array(
+      ':patterns[]' => $ancestors,
     ))
       ->fetchAllKeyed();
 
diff --git a/core/modules/block_content/src/BlockContentForm.php b/core/modules/block_content/src/BlockContentForm.php
index 1b81be23376486252108da0bb7477f3398c2637d..25215c4ed67ae71ba5a70726ae720e14f11201f8 100644
--- a/core/modules/block_content/src/BlockContentForm.php
+++ b/core/modules/block_content/src/BlockContentForm.php
@@ -214,7 +214,7 @@ public function save(array $form, FormStateInterface $form_state) {
    */
   public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($this->entity->isNew()) {
-      $exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue('info')));
+      $exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue(['info', 0, 'value'])));
       if (!empty($exists)) {
         $form_state->setErrorByName('info', $this->t('A block with description %name already exists.', array(
           '%name' => $form_state->getValue(array('info', 0, 'value')),
diff --git a/core/modules/book/src/BookManager.php b/core/modules/book/src/BookManager.php
index cc6b8bb5017ac208a57187a1f2bbb8147938a8af..01077cd0038c70bb3302a16292e4bdefd0f53a01 100644
--- a/core/modules/book/src/BookManager.php
+++ b/core/modules/book/src/BookManager.php
@@ -886,7 +886,7 @@ public function bookTreeCheckAccess(&$tree, $node_links = array()) {
       // @todo This should be actually filtering on the desired node status field
       //   language and just fall back to the default language.
       $nids = \Drupal::entityQuery('node')
-        ->condition('nid', $nids)
+        ->condition('nid', $nids, 'IN')
         ->condition('status', 1)
         ->execute();
 
diff --git a/core/modules/book/src/BookOutlineStorage.php b/core/modules/book/src/BookOutlineStorage.php
index 9af8a60ddb80a2cbf633848195f3e32539dcbce3..66b6a9fad6f5502d427c372930b9d234f215c4b1 100644
--- a/core/modules/book/src/BookOutlineStorage.php
+++ b/core/modules/book/src/BookOutlineStorage.php
@@ -50,7 +50,7 @@ public function hasBooks() {
   public function loadMultiple($nids, $access = TRUE) {
     $query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC));
     $query->fields('b');
-    $query->condition('b.nid', $nids);
+    $query->condition('b.nid', $nids, 'IN');
 
     if ($access) {
       $query->addTag('node_access');
diff --git a/core/modules/comment/src/CommentStatistics.php b/core/modules/comment/src/CommentStatistics.php
index c275f4213c389742f374ae5315a5add49d52d97e..f77a2c1a1e336f50ba05d7a2ccf119060680b136 100644
--- a/core/modules/comment/src/CommentStatistics.php
+++ b/core/modules/comment/src/CommentStatistics.php
@@ -72,7 +72,7 @@ public function read($entities, $entity_type, $accurate = TRUE) {
     $options = $accurate ? array() : array('target' => 'replica');
     $stats =  $this->database->select('comment_entity_statistics', 'ces', $options)
       ->fields('ces')
-      ->condition('ces.entity_id', array_keys($entities))
+      ->condition('ces.entity_id', array_keys($entities), 'IN')
       ->condition('ces.entity_type', $entity_type)
       ->execute();
 
diff --git a/core/modules/comment/src/CommentStorage.php b/core/modules/comment/src/CommentStorage.php
index 7e3e867b225f7e3e7dfc3f886feceafd51e72d93..536559455fb0dc14c505d92aa1b8186022912d89 100644
--- a/core/modules/comment/src/CommentStorage.php
+++ b/core/modules/comment/src/CommentStorage.php
@@ -199,7 +199,7 @@ public function getNewCommentPageNumber($total_comments, $new_comments, Fieldabl
   public function getChildCids(array $comments) {
     return $this->database->select('comment_field_data', 'c')
       ->fields('c', array('cid'))
-      ->condition('pid', array_keys($comments))
+      ->condition('pid', array_keys($comments), 'IN')
       ->condition('default_langcode', 1)
       ->execute()
       ->fetchCol();
diff --git a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
index 8db37c5ea3ad5ac391cbe1354812ed825b2d3762..5aaae545b7484c47aa78a626fa161bf8f30ec7a4 100644
--- a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
+++ b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
@@ -120,11 +120,11 @@ public function preRender(&$values) {
 
     if ($nids) {
       $result = $this->database->query("SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment_field_data} c ON n.nid = c.entity_id AND c.entity_type = 'node' AND c.default_langcode = 1
-        LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN (:nids)
+        LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN ( :nids[] )
         AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp), :timestamp) AND c.status = :status GROUP BY n.nid", array(
         ':status' => CommentInterface::PUBLISHED,
         ':h_uid' => $user->id(),
-        ':nids' => $nids,
+        ':nids[]' => $nids,
         ':timestamp' => HISTORY_READ_LIMIT,
       ));
       foreach ($result as $node) {
diff --git a/core/modules/file/src/Plugin/views/argument/Fid.php b/core/modules/file/src/Plugin/views/argument/Fid.php
index a296a0cb73cd8d3cf9a83224f598a37b7b2a90b9..bca81f762cb86d4c771f8a30903197f48f466a67 100644
--- a/core/modules/file/src/Plugin/views/argument/Fid.php
+++ b/core/modules/file/src/Plugin/views/argument/Fid.php
@@ -75,7 +75,7 @@ public static function create(ContainerInterface $container, array $configuratio
    */
   public function titleQuery() {
     $fids = $this->entityQuery->get('file')
-      ->condition('fid', $this->value)
+      ->condition('fid', $this->value, 'IN')
       ->execute();
     $controller = $this->entityManager->getStorage('file');
     $files = $controller->loadMultiple($fids);
diff --git a/core/modules/forum/src/ForumIndexStorage.php b/core/modules/forum/src/ForumIndexStorage.php
index c7fa74fb7e5d979def0cc622a0bf60270922c648..b50f29b7f001c99310a0cec977c619e1483762ae 100644
--- a/core/modules/forum/src/ForumIndexStorage.php
+++ b/core/modules/forum/src/ForumIndexStorage.php
@@ -58,7 +58,7 @@ public function create(NodeInterface $node) {
   public function read(array $vids) {
     return $this->database->select('forum', 'f')
       ->fields('f', array('nid', 'tid'))
-      ->condition('f.vid', $vids)
+      ->condition('f.vid', $vids, 'IN')
       ->execute();
   }
 
diff --git a/core/modules/forum/src/ForumManager.php b/core/modules/forum/src/ForumManager.php
index ec410dedb5a3381b957a9455acf04515807483ae..da0ded61506959106657b929ebfcae86e4898dbf 100644
--- a/core/modules/forum/src/ForumManager.php
+++ b/core/modules/forum/src/ForumManager.php
@@ -205,7 +205,7 @@ public function getTopics($tid, AccountInterface $account) {
       $query
         ->orderBy('f.sticky', 'DESC')
         ->orderByHeader($header)
-        ->condition('n.nid', $nids)
+        ->condition('n.nid', $nids, 'IN')
         // @todo This should be actually filtering on the desired node language
         //   and just fall back to the default language.
         ->condition('n.default_langcode', 1);
diff --git a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
index f57873455609f89ba93ef07218e34e1627a70209..4b5344a6e54b51313c0dda38024d49c616477e96 100644
--- a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -116,8 +116,9 @@ protected function constructValue($data, $context) {
   public function getUuid($data) {
     if (isset($data['uuid'])) {
       $uuid = $data['uuid'];
-      if (is_array($uuid)) {
-        $uuid = reset($uuid);
+      // The value may be a nested array like $uuid[0]['value'].
+      if (is_array($uuid) && isset($uuid[0]['value'])) {
+        $uuid = $uuid[0]['value'];
       }
       return $uuid;
     }
diff --git a/core/modules/history/history.module b/core/modules/history/history.module
index 57439bba633f3f642be710569b6b5679e87b13a7..1ab9eb6098939c1e881a8e98ec982671acab34e5 100644
--- a/core/modules/history/history.module
+++ b/core/modules/history/history.module
@@ -79,9 +79,9 @@ function history_read_multiple($nids) {
     return $return;
   }
 
-  $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN(:nids)', array(
+  $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN ( :nids[] )', array(
     ':uid' => \Drupal::currentUser()->id(),
-    ':nids' => array_keys($nodes_to_read),
+    ':nids[]' => array_keys($nodes_to_read),
   ));
   foreach ($result as $row) {
     $nodes_to_read[$row->nid] = (int) $row->timestamp;
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index 4e49b81b55cdcade01760747af13fb0621abf786..a8bfbb39aa135e90da9d75151218227742fb6f94 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -406,7 +406,8 @@ protected function defaultImageForm(array &$element, array $settings) {
     );
     // Convert the stored UUID to a FID.
     $fids = [];
-    if ($file = $this->getEntityManager()->loadEntityByUuid('file', $settings['default_image']['uuid'])) {
+    $uuid = $settings['default_image']['uuid'];
+    if ($uuid && ($file = $this->getEntityManager()->loadEntityByUuid('file', $uuid))) {
       $fids[0] = $file->id();
     }
     $element['default_image']['uuid'] = array(
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 3667f93287c372a96622ddcb48d515545b8c2773..0b07f540819cda7b35143cc869b82a83b1f77c1f 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -793,10 +793,10 @@ function locale_translation_update_file_history($file) {
 function locale_translation_file_history_delete($projects = array(), $langcodes = array()) {
   $query = db_delete('locale_file');
   if (!empty($projects)) {
-    $query->condition('project', $projects);
+    $query->condition('project', $projects, 'IN');
   }
   if (!empty($langcodes)) {
-    $query->condition('langcode', $langcodes);
+    $query->condition('langcode', $langcodes, 'IN');
   }
   $query->execute();
 }
diff --git a/core/modules/locale/locale.translation.inc b/core/modules/locale/locale.translation.inc
index 5453f7c1aa832567ac4bc8619b0b83465876849d..544865076ed379b8b563a065106e857b79084746 100644
--- a/core/modules/locale/locale.translation.inc
+++ b/core/modules/locale/locale.translation.inc
@@ -333,7 +333,7 @@ function locale_cron_fill_queue() {
     return $project['status'] == 1;
   });
   $files = db_select('locale_file', 'f')
-    ->condition('f.project', array_keys($projects))
+    ->condition('f.project', array_keys($projects), 'IN')
     ->condition('f.last_checked', $last, '<')
     ->fields('f', array('project', 'langcode'))
     ->execute()->fetchAll();
diff --git a/core/modules/locale/src/StringDatabaseStorage.php b/core/modules/locale/src/StringDatabaseStorage.php
index ea4f12e1cdf2be4e109e50cf48cccef75c5cace4..d09e5a6116e18ed650b95334505c301b5480fe8e 100644
--- a/core/modules/locale/src/StringDatabaseStorage.php
+++ b/core/modules/locale/src/StringDatabaseStorage.php
@@ -93,7 +93,8 @@ public function getLocations(array $conditions = array()) {
     $query = $this->connection->select('locales_location', 'l', $this->options)
       ->fields('l');
     foreach ($conditions as $field => $value) {
-      $query->condition('l.' . $field, $value);
+      // Cast scalars to array so we can consistently use an IN condition.
+      $query->condition('l.' . $field, (array) $value, 'IN');
     }
     return $query->execute()->fetchAll();
   }
@@ -398,13 +399,14 @@ protected function dbStringSelect(array $conditions, array $options = array()) {
     }
 
     // If we have conditions for location's type or name, then we need the
-    // location table, for which we add a subquery.
+    // location table, for which we add a subquery. We cast any scalar value to
+    // array so we can consistently use IN conditions.
     if (isset($conditions['type']) || isset($conditions['name'])) {
       $subquery = $this->connection->select('locales_location', 'l', $this->options)
         ->fields('l', array('sid'));
       foreach (array('type', 'name') as $field) {
         if (isset($conditions[$field])) {
-          $subquery->condition('l.' . $field, $conditions[$field]);
+          $subquery->condition('l.' . $field, (array) $conditions[$field], 'IN');
           unset($conditions[$field]);
         }
       }
@@ -422,12 +424,12 @@ protected function dbStringSelect(array $conditions, array $options = array()) {
         // Conditions for target fields when doing an outer join only make
         // sense if we add also OR field IS NULL.
         $query->condition(db_or()
-            ->condition($field_alias, $value)
+            ->condition($field_alias, (array) $value, 'IN')
             ->isNull($field_alias)
         );
       }
       else {
-        $query->condition($field_alias, $value);
+        $query->condition($field_alias, (array) $value, 'IN');
       }
     }
 
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/VariableMultiRow.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/VariableMultiRow.php
index 7075fcabf4c85418c65e90294753d3dfa856ce16..2ecea8d22ab98307af8a9d3e385c2d5d1b123504 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/VariableMultiRow.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/VariableMultiRow.php
@@ -22,7 +22,8 @@ class VariableMultiRow extends DrupalSqlBase {
   public function query() {
     return $this->select('variable', 'v')
       ->fields('v', array('name', 'value'))
-      ->condition('name', $this->configuration['variables']);
+      // Cast scalars to array so we can consistently use an IN condition.
+      ->condition('name', (array) $this->configuration['variables'], 'IN');
   }
 
   /**
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/CommentVariable.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/CommentVariable.php
index 4921a7198b9fefce9d86ec3d5ba6308e49d22ed2..333e6fa26b0a812478e32e955ad7ec151cba7cc3 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/CommentVariable.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/CommentVariable.php
@@ -45,7 +45,7 @@ protected function getCommentVariables() {
       }
     }
     $return = array();
-    $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN (:name)', array(':name' => $variables))->fetchAllKeyed();
+    $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN ( :name[] )', array(':name[]' => $variables))->fetchAllKeyed();
     foreach ($node_types as $node_type) {
       foreach ($comment_prefixes as $prefix) {
         $name = $prefix . '_' . $node_type;
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/UploadInstance.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/UploadInstance.php
index c8fc5d7f0f0535328f6393de22eb7220a2a0290e..7c9446a3978672c15d36603d5ac4624c18a38048 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/UploadInstance.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/UploadInstance.php
@@ -33,7 +33,7 @@ protected function runQuery() {
     $max_filesize = $max_filesize ? $max_filesize . 'MB' : '';
     $file_extensions = $this->variableGet('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp');
     $return = array();
-    $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN (:name)', array(':name' => $variables))->fetchAllKeyed();
+    $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN ( :name[] )', array(':name[]' => $variables))->fetchAllKeyed();
     foreach ($node_types as $node_type) {
       $name = $prefix . '_' . $node_type;
       if (isset($values[$name])) {
diff --git a/core/modules/node/src/Plugin/views/argument/Vid.php b/core/modules/node/src/Plugin/views/argument/Vid.php
index 29f91dac9a12091a00470ecb0ed06b1633e14c27..43246d80e4895ffb93778aafccce565019422d19 100644
--- a/core/modules/node/src/Plugin/views/argument/Vid.php
+++ b/core/modules/node/src/Plugin/views/argument/Vid.php
@@ -74,7 +74,7 @@ public static function create(ContainerInterface $container, array $configuratio
   public function titleQuery() {
     $titles = array();
 
-    $results = $this->database->query('SELECT nr.vid, nr.nid, npr.title FROM {node_revision} nr WHERE nr.vid IN (:vids)', array(':vids' => $this->value))->fetchAllAssoc('vid', PDO::FETCH_ASSOC);
+    $results = $this->database->query('SELECT nr.vid, nr.nid, npr.title FROM {node_revision} nr WHERE nr.vid IN ( :vids[] )', array(':vids[]' => $this->value))->fetchAllAssoc('vid', PDO::FETCH_ASSOC);
     $nids = array();
     foreach ($results as $result) {
       $nids[] = $result['nid'];
diff --git a/core/modules/node/src/Plugin/views/filter/UidRevision.php b/core/modules/node/src/Plugin/views/filter/UidRevision.php
index 7b43cc64e6bd859994e89f9c904e9af8fe3c750d..39e0a7b4e6b5b06343cc193f648d38eba3dc6786 100644
--- a/core/modules/node/src/Plugin/views/filter/UidRevision.php
+++ b/core/modules/node/src/Plugin/views/filter/UidRevision.php
@@ -21,7 +21,7 @@ class UidRevision extends Name {
   public function query($group_by = FALSE) {
     $this->ensureMyTable();
 
-    $placeholder = $this->placeholder();
+    $placeholder = $this->placeholder() . '[]';
 
     $args = array_values($this->value);
 
diff --git a/core/modules/options/options.module b/core/modules/options/options.module
index 54cf4b3830ae9b6d62f85f4d1a45c29be142cb44..a2e8f06aefc9c2eccaa9c608533a124f7675be1d 100644
--- a/core/modules/options/options.module
+++ b/core/modules/options/options.module
@@ -124,7 +124,7 @@ function _options_values_in_use($entity_type, $field_name, $values) {
   if ($values) {
     $factory = \Drupal::service('entity.query');
     $result = $factory->get($entity_type)
-      ->condition($field_name . '.value', $values)
+      ->condition($field_name . '.value', $values, 'IN')
       ->count()
       ->accessCheck(FALSE)
       ->range(0, 1)
diff --git a/core/modules/system/src/Tests/Database/QueryTest.php b/core/modules/system/src/Tests/Database/QueryTest.php
index 98e0e8bc6ad9d836ad68e9273498c40cec703d34..64e7b42960bc0c6bba387b130e827e4e81147576 100644
--- a/core/modules/system/src/Tests/Database/QueryTest.php
+++ b/core/modules/system/src/Tests/Database/QueryTest.php
@@ -7,21 +7,36 @@
 
 namespace Drupal\system\Tests\Database;
 
-use Drupal\Core\Database\DatabaseExceptionWrapper;
-
 /**
  * Tests Drupal's extended prepared statement syntax..
  *
  * @group Database
  */
 class QueryTest extends DatabaseTestBase {
+
   /**
    * Tests that we can pass an array of values directly in the query.
    */
   function testArraySubstitution() {
-    $names = db_query('SELECT name FROM {test} WHERE age IN (:ages) ORDER BY age', array(':ages' => array(25, 26, 27)))->fetchAll();
-
+    $names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => array(25, 26, 27)))->fetchAll();
     $this->assertEqual(count($names), 3, 'Correct number of names returned');
+
+    $names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => array(25)))->fetchAll();
+    $this->assertEqual(count($names), 1, 'Correct number of names returned');
+  }
+
+  /**
+   * Tests that we can not pass a scalar value when an array is expected.
+   */
+  function testScalarSubstitution() {
+    try {
+      $names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => 25))->fetchAll();
+      $this->fail('Array placeholder with scalar argument should result in an exception.');
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->pass('Array placeholder with scalar argument should result in an exception.');
+    }
+
   }
 
   /**
@@ -37,7 +52,7 @@ public function testArrayArgumentsSQLInjection() {
       db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => $condition))->fetchObject();
       $this->fail('SQL injection attempt via array arguments should result in a database exception.');
     }
-    catch (DatabaseExceptionWrapper $e) {
+    catch (\InvalidArgumentException $e) {
       $this->pass('SQL injection attempt via array arguments should result in a database exception.');
     }
 
diff --git a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
index 6289c03144e643ce75351e5caccd855a1203d886..2e8a3b32b3f7e99c6eba0aacc8ddda8c25237fb7 100644
--- a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
@@ -264,11 +264,11 @@ protected function doTestMultilingualProperties($entity_type) {
     // query.
     $query = \Drupal::entityQuery($entity_type);
     $group = $query->andConditionGroup()
-      ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode)
-      ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode);
+      ->condition('user_id', $properties[$default_langcode]['user_id'][0], '=', $default_langcode)
+      ->condition('name', $properties[$default_langcode]['name'][0], '=', $default_langcode);
     $result = $query
       ->condition($group)
-      ->condition('name', $properties[$langcode]['name'], '=', $langcode)
+      ->condition('name', $properties[$langcode]['name'][0], '=', $langcode)
       ->execute();
     $this->assertEqual(count($result), 1, format_string('%entity_type: One entity loaded by name and uid using different language meta conditions.', array('%entity_type' => $entity_type)));
 
@@ -279,10 +279,10 @@ protected function doTestMultilingualProperties($entity_type) {
     $entity->save();
     $query = \Drupal::entityQuery($entity_type);
     $default_langcode_group = $query->andConditionGroup()
-      ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode)
-      ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode);
+      ->condition('user_id', $properties[$default_langcode]['user_id'][0], '=', $default_langcode)
+      ->condition('name', $properties[$default_langcode]['name'][0], '=', $default_langcode);
     $langcode_group = $query->andConditionGroup()
-      ->condition('name', $properties[$langcode]['name'], '=', $langcode)
+      ->condition('name', $properties[$langcode]['name'][0], '=', $langcode)
       ->condition("$this->field_name.value", $field_value, '=', $langcode);
     $result = $query
       ->condition($langcode_key, $default_langcode)
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index c158de437d3e06dbe8e071d3cbbba0ebf3005f7a..d41097f73106a9c9f9cbdea0fb47a754f89c182f 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -363,7 +363,7 @@ function validate_term_strings(&$form, $values, FormStateInterface $form_state)
     }
 
     $query = \Drupal::entityQuery('taxonomy_term')
-      ->condition('name', $names)
+      ->condition('name', $names, 'IN')
       ->condition('vid', $this->options['vid'])
       ->addTag('term_access');
     $terms = Term::loadMultiple($query->execute());
diff --git a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
index b6fed8b05937fdd0850a837a05f18fb163407309..a49b4ec7de991bfe0a0804f3090a2692df566bb0 100644
--- a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
+++ b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
@@ -136,7 +136,7 @@ public function query() {
 
       $query = db_select('taxonomy_term_data', 'td');
       $query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
-      $query->condition('td.vid', array_filter($this->options['vids']));
+      $query->condition('td.vid', array_filter($this->options['vids']), 'IN');
       $query->addTag('term_access');
       $query->fields('td');
       $query->fields('tn', array('nid'));
diff --git a/core/modules/taxonomy/src/TermStorage.php b/core/modules/taxonomy/src/TermStorage.php
index 32c364317994e21ee241944a99637c192e1e2534..60b233043ef5f70dc08eb2e1b230b3894854fa65 100644
--- a/core/modules/taxonomy/src/TermStorage.php
+++ b/core/modules/taxonomy/src/TermStorage.php
@@ -101,7 +101,7 @@ public function resetCache(array $ids = NULL) {
    */
   public function deleteTermHierarchy($tids) {
     $this->database->delete('taxonomy_term_hierarchy')
-      ->condition('tid', $tids)
+      ->condition('tid', $tids, 'IN')
       ->execute();
   }
 
diff --git a/core/modules/taxonomy/src/VocabularyStorage.php b/core/modules/taxonomy/src/VocabularyStorage.php
index 3d6cef165f8fef065eaec74fd73fe07b2c817c0a..6eeed05aafee9e29e4d985a50a7ec100f4cbf4a1 100644
--- a/core/modules/taxonomy/src/VocabularyStorage.php
+++ b/core/modules/taxonomy/src/VocabularyStorage.php
@@ -27,7 +27,7 @@ public function resetCache(array $ids = NULL) {
    * {@inheritdoc}
    */
   public function getToplevelTids($vids) {
-    return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN (:vids) AND th.parent = 0', array(':vids' => $vids))->fetchCol();
+    return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN ( :vids[] ) AND th.parent = 0', array(':vids[]' => $vids))->fetchCol();
   }
 
 }
diff --git a/core/modules/tracker/src/Plugin/views/filter/UserUid.php b/core/modules/tracker/src/Plugin/views/filter/UserUid.php
index 0b837f67f8fdecb64037fe23d43af5c990f8ba0c..cb9b2328e9b94dbdba03afab3b3b9f7e21046771 100644
--- a/core/modules/tracker/src/Plugin/views/filter/UserUid.php
+++ b/core/modules/tracker/src/Plugin/views/filter/UserUid.php
@@ -26,7 +26,8 @@ public function query() {
     // table, we need to make sure {tracker_user} is JOINed and use its alias
     // for the WHERE clause.
     $tracker_user_alias = $this->query->ensureTable('tracker_user');
-    $this->query->addWhere(0, "$tracker_user_alias.uid", $this->value);
+    // Cast scalars to array so we can consistently use an IN condition.
+    $this->query->addWhere(0, "$tracker_user_alias.uid", (array) $this->value, 'IN');
   }
 
 }
diff --git a/core/modules/user/src/Plugin/views/field/Roles.php b/core/modules/user/src/Plugin/views/field/Roles.php
index cae153c34b8196c42a38c73c74987b857a518dc3..3f38496bcf15c7db80c56e6f9c6b1b89edff3bae 100644
--- a/core/modules/user/src/Plugin/views/field/Roles.php
+++ b/core/modules/user/src/Plugin/views/field/Roles.php
@@ -79,7 +79,7 @@ public function preRender(&$values) {
 
     if ($uids) {
       $roles = user_roles();
-      $result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN (:uids) AND u.roles_target_id IN (:rids)', array(':uids' => $uids, ':rids' => array_keys($roles)));
+      $result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN ( :uids[] ) AND u.roles_target_id IN ( :rids[] )', array(':uids[]' => $uids, ':rids[]' => array_keys($roles)));
       foreach ($result as $role) {
         $this->items[$role->uid][$role->rid]['role'] = String::checkPlain($roles[$role->rid]->label());
         $this->items[$role->uid][$role->rid]['rid'] = $role->rid;
diff --git a/core/modules/user/src/Tests/UserDeleteTest.php b/core/modules/user/src/Tests/UserDeleteTest.php
index 84bacb1b0370daceb7e96526225f472a4159c4da..bfa6016d15e7127023241a5b795878d7ad545176 100644
--- a/core/modules/user/src/Tests/UserDeleteTest.php
+++ b/core/modules/user/src/Tests/UserDeleteTest.php
@@ -31,7 +31,7 @@ function testUserDeleteMultiple() {
     $query = db_select('user__roles', 'r');
     $roles_created = $query
       ->fields('r', array('entity_id'))
-      ->condition('entity_id', $uids)
+      ->condition('entity_id', $uids, 'IN')
       ->countQuery()
       ->execute()
       ->fetchField();
@@ -45,7 +45,7 @@ function testUserDeleteMultiple() {
     $query = db_select('user__roles', 'r');
     $roles_after_deletion = $query
       ->fields('r', array('entity_id'))
-      ->condition('entity_id', $uids)
+      ->condition('entity_id', $uids, 'IN')
       ->countQuery()
       ->execute()
       ->fetchField();
diff --git a/core/modules/user/src/UserData.php b/core/modules/user/src/UserData.php
index 0814ac50153d1f75ed6fdd3b3b49538f4c52554e..3f6b5931811dd73edad76c8c6fb16243a9bb9306 100644
--- a/core/modules/user/src/UserData.php
+++ b/core/modules/user/src/UserData.php
@@ -106,14 +106,15 @@ public function set($module, $uid, $name, $value) {
    */
   public function delete($module = NULL, $uid = NULL, $name = NULL) {
     $query = $this->connection->delete('users_data');
+    // Cast scalars to array so we can consistently use an IN condition.
     if (isset($module)) {
-      $query->condition('module', $module);
+      $query->condition('module', (array) $module, 'IN');
     }
     if (isset($uid)) {
-      $query->condition('uid', $uid);
+      $query->condition('uid', (array) $uid, 'IN');
     }
     if (isset($name)) {
-      $query->condition('name', $name);
+      $query->condition('name', (array) $name, 'IN');
     }
     $query->execute();
   }
diff --git a/core/modules/views/src/ManyToOneHelper.php b/core/modules/views/src/ManyToOneHelper.php
index 51e6e63dc9e91cf09f1dc22dd4ef21ecb0f985f4..0c2180115972c6e49b49d85d5412685b66e8fc5d 100644
--- a/core/modules/views/src/ManyToOneHelper.php
+++ b/core/modules/views/src/ManyToOneHelper.php
@@ -310,6 +310,7 @@ public function addFilter() {
       else {
         $placeholder = $this->placeholder();
         if (count($this->handler->value) > 1) {
+          $placeholder .= '[]';
           $this->handler->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value));
         }
         else {
diff --git a/core/modules/views/src/Plugin/views/argument/Numeric.php b/core/modules/views/src/Plugin/views/argument/Numeric.php
index bfa0bcaaff4bc6db2354b79a3f6f26806a06fdc6..e926da3fc89f7d12494d2b025f728c4128fdf4cd 100644
--- a/core/modules/views/src/Plugin/views/argument/Numeric.php
+++ b/core/modules/views/src/Plugin/views/argument/Numeric.php
@@ -113,6 +113,7 @@ public function query($group_by = FALSE) {
 
     if (count($this->value) > 1) {
       $operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
+      $placeholder .= '[]';
       $this->query->addWhereExpression(0, "$this->tableAlias.$this->realField $operator($placeholder) $null_check", array($placeholder => $this->value));
     }
     else {
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index 3af0e9c621976efac059890916be6afece9dce02..7c104d86a1fe81d7a155646a2a1fe56b63a4da08 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -1357,7 +1357,7 @@ public function acceptExposedInput($input) {
       }
       if (isset($value)) {
         $this->value = $value;
-        if (empty($this->alwaysMultiple) && empty($this->options['expose']['multiple'])) {
+        if (empty($this->alwaysMultiple) && empty($this->options['expose']['multiple']) && !is_array($value)) {
           $this->value = array($value);
         }
       }
diff --git a/core/modules/views/src/Tests/Handler/FilterEqualityTest.php b/core/modules/views/src/Tests/Handler/FilterEqualityTest.php
index fb9300d7b441baaed7062ff8e6fd6be47ff02d61..2a59e9f22bb02c1c1830508ecfee15d3ef2b56e8 100644
--- a/core/modules/views/src/Tests/Handler/FilterEqualityTest.php
+++ b/core/modules/views/src/Tests/Handler/FilterEqualityTest.php
@@ -54,7 +54,7 @@ function testEqual() {
         'field' => 'name',
         'relationship' => 'none',
         'operator' => '=',
-        'value' => array('value' => 'Ringo'),
+        'value' => 'Ringo',
       ),
     ));
 
@@ -98,7 +98,7 @@ function testNotEqual() {
         'field' => 'name',
         'relationship' => 'none',
         'operator' => '!=',
-        'value' => array('value' => 'Ringo'),
+        'value' => 'Ringo',
       ),
     ));
 
@@ -172,12 +172,12 @@ protected function getGroupedExposedFilters() {
             1 => array(
               'title' => 'Name is equal to Ringo',
               'operator' => '=',
-              'value' => array('value' => 'Ringo'),
+              'value' => 'Ringo',
             ),
             2 => array(
               'title' => 'Name is not equal to Ringo',
               'operator' => '!=',
-              'value' => array('value' => 'Ringo'),
+              'value' => 'Ringo',
             ),
           ),
         ),
diff --git a/core/modules/views/src/Tests/Handler/FilterStringTest.php b/core/modules/views/src/Tests/Handler/FilterStringTest.php
index bcf84a785184b49f3f837744bc0b02a0b84ea2c3..baa34893b1e88201591534c88922ccba2ed8c058 100644
--- a/core/modules/views/src/Tests/Handler/FilterStringTest.php
+++ b/core/modules/views/src/Tests/Handler/FilterStringTest.php
@@ -144,7 +144,7 @@ function testFilterStringNotEqual() {
         'field' => 'name',
         'relationship' => 'none',
         'operator' => '!=',
-        'value' => array('value' => 'Ringo'),
+        'value' => 'Ringo',
       ),
     ));
 
@@ -756,7 +756,7 @@ protected function getGroupedExposedFilters() {
             2 => array(
               'title' => 'Is not Ringo',
               'operator' => '!=',
-              'value' => array('value' => 'Ringo'),
+              'value' => 'Ringo',
             ),
             3 => array(
               'title' => 'Contains ing',
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 2fa3b9e159bd6a2e631905db540620b64e06ad33..ac3ba0cb483d38011d35205a258dcc847cd5c000 100644
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -1151,8 +1151,8 @@ function simpletest_script_load_messages_by_test_id($test_ids) {
 
   foreach ($test_id_chunks as $test_id_chunk) {
     $result_chunk = Database::getConnection('default', 'test-runner')
-      ->query("SELECT * FROM {simpletest} WHERE test_id IN (:test_ids) ORDER BY test_class, message_id", array(
-        ':test_ids' => $test_id_chunk,
+      ->query("SELECT * FROM {simpletest} WHERE test_id IN ( :test_ids[] ) ORDER BY test_class, message_id", array(
+        ':test_ids[]' => $test_id_chunk,
       ))->fetchAll();
     if ($result_chunk) {
       $results = array_merge($results, $result_chunk);