diff --git a/core/lib/Drupal/Core/Cache/Cache.php b/core/lib/Drupal/Core/Cache/Cache.php
index ff24324..f282a77 100644
--- a/core/lib/Drupal/Core/Cache/Cache.php
+++ b/core/lib/Drupal/Core/Cache/Cache.php
@@ -37,6 +37,7 @@ public static function mergeContexts() {
       $cache_contexts = array_merge($cache_contexts, $contexts);
     }
     $cache_contexts = array_unique($cache_contexts);
+    \Drupal::service('cache_contexts')->validate($cache_contexts);
     sort($cache_contexts);
     return $cache_contexts;
   }
@@ -62,10 +63,10 @@ public static function mergeTags() {
     $cache_tag_arrays = func_get_args();
     $cache_tags = [];
     foreach ($cache_tag_arrays as $tags) {
-      static::validateTags($tags);
       $cache_tags = array_merge($cache_tags, $tags);
     }
     $cache_tags = array_unique($cache_tags);
+    static::validateTags($cache_tags);
     sort($cache_tags);
     return $cache_tags;
   }
diff --git a/core/lib/Drupal/Core/Cache/CacheContexts.php b/core/lib/Drupal/Core/Cache/CacheContexts.php
index 33f86b1..4981539 100644
--- a/core/lib/Drupal/Core/Cache/CacheContexts.php
+++ b/core/lib/Drupal/Core/Cache/CacheContexts.php
@@ -54,6 +54,44 @@ public function __construct(ContainerInterface $container, array $contexts) {
     $this->contexts = $contexts;
   }
 
+  public function validate(array $context_tokens = []) {
+    if (empty($context_tokens)) {
+      return;
+    }
+
+    // Initialize the set of valid context tokens with the container's contexts.
+    if (!isset($this->validContextTokens)) {
+      $this->validContextTokens = array_flip($this->contexts);
+    }
+
+    foreach ($context_tokens as $context_token) {
+      if (!is_string($context_token)) {
+        throw new \LogicException('Cache contexts must be strings, ' . gettype($context_token) . ' given.');
+      }
+
+      if (isset($this->validContextTokens[$context_token])) {
+        continue;
+      }
+
+      // If it's a valid context token, then the ID must be stored in the set
+      // of valid context tokens (since we initialized it with the list of cache
+      // context IDs using the container). In case of an invalid context token,
+      // throw an exception, otherwise cache it, including the parameter, to
+      // minimize the amount of work in future ::validateContexts() calls.
+      $context_id = $context_token;
+      $colon_pos = strpos($context_id, ':');
+      if ($colon_pos !== FALSE) {
+        $context_id = substr($context_id, 0, $colon_pos);
+      }
+      if (isset($this->validContextTokens[$context_id])) {
+        $this->validContextTokens[$context_token] = TRUE;
+      }
+      else {
+        throw new \LogicException('"' . $context_id . '" is not a valid cache context ID.');
+      }
+    }
+  }
+
   /**
    * Provides an array of available cache contexts.
    *
diff --git a/core/modules/entity_reference/src/Tests/Views/EntityReferenceRelationshipTest.php b/core/modules/entity_reference/src/Tests/Views/EntityReferenceRelationshipTest.php
index 9ae79a7..f2a803d 100644
--- a/core/modules/entity_reference/src/Tests/Views/EntityReferenceRelationshipTest.php
+++ b/core/modules/entity_reference/src/Tests/Views/EntityReferenceRelationshipTest.php
@@ -52,8 +52,6 @@ protected function setUp() {
     $this->installEntitySchema('user');
     $this->installEntitySchema('entity_test');
 
-    ViewTestData::createTestViews(get_class($this), array('entity_reference_test_views'));
-
     $field_storage = FieldStorageConfig::create(array(
       'entity_type' => 'entity_test',
       'field_name' => 'field_test',
@@ -76,6 +74,8 @@ protected function setUp() {
     ));
     $field->save();
 
+    ViewTestData::createTestViews(get_class($this), array('entity_reference_test_views'));
+
     // Create some test entities which link each other.
     $entity_storage= \Drupal::entityManager()->getStorage('entity_test');
     $referenced_entity = $entity_storage->create(array());
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_view.yml b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_view.yml
index c60ede7..90e4d31 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_view.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test_views/test_views/views.view.test_entity_reference_view.yml
@@ -67,7 +67,7 @@ display:
         test_relationship:
           id: reverse_field_test
           table: entity_test
-          field: reverse_field_test
+          field: reverse__entity_test__field_test
           relationship: none
           plugin_id: standard
     display_plugin: embed
diff --git a/core/modules/node/src/Plugin/views/argument_default/Node.php b/core/modules/node/src/Plugin/views/argument_default/Node.php
index 4a61f03..e6d8343 100644
--- a/core/modules/node/src/Plugin/views/argument_default/Node.php
+++ b/core/modules/node/src/Plugin/views/argument_default/Node.php
@@ -83,7 +83,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.url'];
+    return ['url'];
   }
 
 }
diff --git a/core/modules/node/src/Plugin/views/filter/Access.php b/core/modules/node/src/Plugin/views/filter/Access.php
index 5fd6924..d56edcd 100644
--- a/core/modules/node/src/Plugin/views/filter/Access.php
+++ b/core/modules/node/src/Plugin/views/filter/Access.php
@@ -53,8 +53,7 @@ public function query() {
   public function getCacheContexts() {
     $contexts = parent::getCacheContexts();
 
-    // Node access is potentially cacheable per user.
-    $contexts[] = 'cache.context.user';
+    $contexts[] = 'node_view_grants';
 
     return $contexts;
   }
diff --git a/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
index 1523421..a9330ba 100644
--- a/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
+++ b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
@@ -58,11 +58,13 @@ protected function assertPageCacheContextsAndTags(Url $url, array $expected_cont
     $actual_tags = $get_cache_header_values('X-Drupal-Cache-Tags');
     $this->assertIdentical($actual_contexts, $expected_contexts);
     if ($actual_contexts !== $expected_contexts) {
-      debug(array_diff($actual_contexts, $expected_contexts));
+      debug('Missing cache contexts: ' . implode(',', array_diff($actual_contexts, $expected_contexts)));
+      debug('Unwanted cache contexts: ' . implode(',', array_diff($expected_contexts, $actual_contexts)));
     }
     $this->assertIdentical($actual_tags, $expected_tags);
     if ($actual_tags !== $expected_tags) {
-      debug(array_diff($actual_tags, $expected_tags));
+      debug('Missing cache tags: ' . implode(',', array_diff($actual_tags, $expected_tags)));
+      debug('Unwanted cache tags: ' . implode(',', array_diff($expected_tags, $actual_tags)));
     }
 
     // Assert cache hit + expected cache contexts + tags.
@@ -72,11 +74,13 @@ protected function assertPageCacheContextsAndTags(Url $url, array $expected_cont
     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
     $this->assertIdentical($actual_contexts, $expected_contexts);
     if ($actual_contexts !== $expected_contexts) {
-      debug(array_diff($actual_contexts, $expected_contexts));
+      debug('Missing cache contexts: ' . implode(',', array_diff($actual_contexts, $expected_contexts)));
+      debug('Unwanted cache contexts: ' . implode(',', array_diff($expected_contexts, $actual_contexts)));
     }
     $this->assertIdentical($actual_tags, $expected_tags);
     if ($actual_tags !== $expected_tags) {
-      debug(array_diff($actual_tags, $expected_tags));
+      debug('Missing cache tags: ' . implode(',', array_diff($actual_tags, $expected_tags)));
+      debug('Unwanted cache tags: ' . implode(',', array_diff($expected_tags, $actual_tags)));
     }
 
     // Assert page cache item + expected cache tags.
@@ -86,7 +90,8 @@ protected function assertPageCacheContextsAndTags(Url $url, array $expected_cont
     sort($cache_entry->tags);
     $this->assertEqual($cache_entry->tags, $expected_tags);
     if ($cache_entry->tags !== $expected_tags) {
-      debug(array_diff($cache_entry->tags, $expected_tags));
+      debug('Missing cache tags: ' . implode(',', array_diff($cache_entry->tags, $expected_tags)));
+      debug('Unwanted cache tags: ' . implode(',', array_diff($expected_tags, $cache_entry->tags)));
     }
   }
 
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.services.yml b/core/modules/system/tests/modules/entity_test/entity_test.services.yml
index 8769fbc..75e1bf3 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.services.yml
+++ b/core/modules/system/tests/modules/entity_test/entity_test.services.yml
@@ -4,3 +4,7 @@ services:
     arguments: ['@state']
     tags:
       - { name: event_subscriber }
+  cache_context.entity_test_view_grants:
+    class: Drupal\entity_test\Cache\EntityTestViewGrantsCacheContext
+    tags:
+      - { name: cache.context }
diff --git a/core/modules/system/tests/modules/entity_test/src/Cache/EntityTestViewGrantsCacheContext.php b/core/modules/system/tests/modules/entity_test/src/Cache/EntityTestViewGrantsCacheContext.php
new file mode 100644
index 0000000..b93f404
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/Cache/EntityTestViewGrantsCacheContext.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity_test\Cache\EntityTestViewViewGrantsCacheContext.
+ */
+
+namespace Drupal\entity_test\Cache;
+
+use Drupal\Core\Cache\CacheContextInterface;
+
+/**
+ * Defines the entity_test view grants cache context service.
+ *
+ * @see \Drupal\node\Cache\NodeAccessViewGrantsCacheContext
+ */
+class EntityTestViewViewGrantsCacheContext implements CacheContextInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getLabel() {
+    return t("Entity test view grants");
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContext() {
+    return hash('sha256', REQUEST_TIME);
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
index 5bd3f45..a8751d5 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
@@ -230,7 +230,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.url'];
+    return ['url'];
   }
 
   /**
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index 573448d..1b8ead7 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -360,7 +360,7 @@ public function getCacheContexts() {
     // The result potentially depends on term access and so is just cacheable
     // per user.
     // @todo https://www.drupal.org/node/2352175
-    $contexts[] = 'cache.context.user';
+    $contexts[] = 'user';
 
     return $contexts;
   }
diff --git a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
index 1d49666..3b2f2a8 100644
--- a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
+++ b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
@@ -37,7 +37,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.user'];
+    return ['user'];
   }
 
 }
diff --git a/core/modules/user/src/Plugin/views/argument_default/User.php b/core/modules/user/src/Plugin/views/argument_default/User.php
index e3d9644..269be4e 100644
--- a/core/modules/user/src/Plugin/views/argument_default/User.php
+++ b/core/modules/user/src/Plugin/views/argument_default/User.php
@@ -123,7 +123,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.url'];
+    return ['url'];
   }
 
 }
diff --git a/core/modules/user/src/Plugin/views/filter/Current.php b/core/modules/user/src/Plugin/views/filter/Current.php
index 6bf0f29..d619f14 100644
--- a/core/modules/user/src/Plugin/views/filter/Current.php
+++ b/core/modules/user/src/Plugin/views/filter/Current.php
@@ -54,7 +54,7 @@ public function getCacheContexts() {
     $contexts = parent::getCacheContexts();
 
     // This filter depends on the current user.
-    $contexts[] = 'cache.context.user';
+    $contexts[] = 'user';
 
     return $contexts;
   }
diff --git a/core/modules/views/src/Entity/Render/RendererBase.php b/core/modules/views/src/Entity/Render/RendererBase.php
index be8aea6..d4694d2 100644
--- a/core/modules/views/src/Entity/Render/RendererBase.php
+++ b/core/modules/views/src/Entity/Render/RendererBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
@@ -16,7 +17,7 @@
 /**
  * Defines a base class for entity row renderers.
  */
-abstract class RendererBase {
+abstract class RendererBase implements CacheablePluginInterface {
 
   /**
    * The view executable wrapping the view storage entity.
@@ -63,6 +64,20 @@ public function __construct(ViewExecutable $view, LanguageManagerInterface $lang
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    return ['language'];
+  }
+
+  /**
    * Returns the language code associated to the given row.
    *
    * @param \Drupal\views\ResultRow $row
diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php
index 51ad1a6..40d3d4c 100644
--- a/core/modules/views/src/Entity/View.php
+++ b/core/modules/views/src/Entity/View.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Entity;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\views\Views;
@@ -317,8 +318,7 @@ protected function addCacheMetadata() {
       list($display['cache_metadata']['cacheable'], $display['cache_metadata']['contexts']) = $executable->getDisplay()->calculateCacheMetadata();
       // Always include at least the language context as there will be most
       // probable translatable strings in the view output.
-      $display['cache_metadata']['contexts'][] = 'language';
-      $display['cache_metadata']['contexts'] = array_unique($display['cache_metadata']['contexts']);
+      $display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['language']);
     }
     // Restore the previous active display.
     $executable->setDisplay($current_display);
diff --git a/core/modules/views/src/Plugin/CacheablePluginInterface.php b/core/modules/views/src/Plugin/CacheablePluginInterface.php
index a8a72a9..b700ce7 100644
--- a/core/modules/views/src/Plugin/CacheablePluginInterface.php
+++ b/core/modules/views/src/Plugin/CacheablePluginInterface.php
@@ -8,7 +8,9 @@
 namespace Drupal\views\Plugin;
 
 /**
- * Provides information whether and how the specific Views plugin is cacheable.
+ * Provides caching information about the result cacheability of views plugins.
+ *
+ * For caching on the render level, we rely on bubbling of the cache contexts.
  */
 interface CacheablePluginInterface {
 
diff --git a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
index 069276b..4e5469b 100644
--- a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
@@ -1208,7 +1208,7 @@ public function getCacheContexts() {
     // By definition arguments depends on the URL.
     // @todo Once contexts are properly injected into block views we could pull
     //   the information from there.
-    $contexts[] = 'cache.context.url';
+    $contexts[] = 'url';
 
     // Asks all subplugins (argument defaults, argument validator and styles).
     if (($plugin = $this->getPlugin('argument_default')) && $plugin instanceof CacheablePluginInterface) {
diff --git a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
index 337b722..feccd21 100644
--- a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
+++ b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
@@ -95,7 +95,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.url'];
+    return ['url'];
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/argument_default/Raw.php b/core/modules/views/src/Plugin/views/argument_default/Raw.php
index 4239c50..40bddf3 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Raw.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Raw.php
@@ -124,7 +124,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    return ['cache.context.url'];
+    return ['url'];
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/field/Field.php b/core/modules/views/src/Plugin/views/field/Field.php
index 46d3f5f..e34d4a1 100644
--- a/core/modules/views/src/Plugin/views/field/Field.php
+++ b/core/modules/views/src/Plugin/views/field/Field.php
@@ -961,10 +961,7 @@ public function isCacheable() {
    * {@inheritdoc}
    */
   public function getCacheContexts() {
-    // @todo what to do about field access?
-    $contexts = [];
-
-    $contexts[] = 'user';
+    $contexts = $this->getEntityTranslationRenderer()->getCacheContexts();
 
     return $contexts;
   }
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index b5f8bf8..9abf63e 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -1477,7 +1477,7 @@ public function getCacheContexts() {
     // input from GET parameters, which are part of the URL. Hence a view with
     // an exposed filter is cacheable per URL.
     if ($this->isExposed()) {
-      $cache_contexts[] = 'cache.context.url';
+      $cache_contexts[] = 'url';
     }
     return $cache_contexts;
   }
diff --git a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
index 45b86be..8fe2b43 100644
--- a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
+++ b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
@@ -241,7 +241,7 @@ public function getCacheContexts() {
     $cache_contexts = [];
     // Exposed sorts use GET parameters, so it depends on the current URL.
     if ($this->isExposed()) {
-      $cache_contexts[] = 'cache.context.url';
+      $cache_contexts[] = 'url';
     }
     return $cache_contexts;
   }
diff --git a/core/modules/views/src/Tests/Entity/FieldEntityTest.php b/core/modules/views/src/Tests/Entity/FieldEntityTest.php
index 37e27c0..715a36b 100644
--- a/core/modules/views/src/Tests/Entity/FieldEntityTest.php
+++ b/core/modules/views/src/Tests/Entity/FieldEntityTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\comment\Tests\CommentTestTrait;
 use Drupal\views\Tests\ViewTestBase;
+use Drupal\views\Tests\ViewTestData;
 use Drupal\views\Views;
 
 /**
@@ -35,6 +36,19 @@ class FieldEntityTest extends ViewTestBase {
   public static $modules = array('node', 'comment');
 
   /**
+   * {@inheritdoc}
+   */
+  protected function setUp($import_test_views = TRUE) {
+    parent::setUp(FALSE);
+
+    $this->drupalCreateContentType(array('type' => 'page'));
+    $this->addDefaultCommentField('node', 'page');
+
+    ViewTestData::createTestViews(get_class($this), array('views_test_config'));
+  }
+
+
+  /**
    * Tests the getEntity method.
    */
   public function testGetEntity() {
@@ -43,8 +57,6 @@ public function testGetEntity() {
 
     $account = entity_create('user', array('name' => $this->randomMachineName(), 'bundle' => 'user'));
     $account->save();
-    $this->drupalCreateContentType(array('type' => 'page'));
-    $this->addDefaultCommentField('node', 'page');
 
     $node = entity_create('node', array('uid' => $account->id(), 'type' => 'page'));
     $node->save();
diff --git a/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php b/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php
index d96f666..8805214 100644
--- a/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php
+++ b/core/modules/views/src/Tests/Entity/ViewEntityDependenciesTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\views\Tests\ViewTestData;
 use Drupal\views\Tests\ViewUnitTestBase;
 use Drupal\views\Views;
 
@@ -37,16 +38,11 @@ class ViewEntityDependenciesTest extends ViewUnitTestBase {
    * {@inheritdoc}
    */
   protected function setUp() {
-    parent::setUp();
+    parent::setUp(FALSE);
+
     // Install the necessary dependencies for node type creation to work.
     $this->installEntitySchema('node');
     $this->installConfig(array('field', 'node'));
-  }
-
-  /**
-   * Tests the calculateDependencies method.
-   */
-  public function testCalculateDependencies() {
 
     $comment_type = entity_create('comment_type', array(
       'id' => 'comment',
@@ -55,6 +51,7 @@ public function testCalculateDependencies() {
       'target_entity_type_id' => 'node',
     ));
     $comment_type->save();
+
     $content_type = entity_create('node_type', array(
       'type' => $this->randomMachineName(),
       'name' => $this->randomString(),
@@ -82,6 +79,13 @@ public function testCalculateDependencies() {
       'settings' => array('display_summary' => TRUE),
     ))->save();
 
+    ViewTestData::createTestViews(get_class($this), array('views_test_config'));
+  }
+
+  /**
+   * Tests the calculateDependencies method.
+   */
+  public function testCalculateDependencies() {
     $expected = [];
     $expected['test_field_get_entity'] = [
       'module' => [
diff --git a/core/modules/views/src/Tests/GlossaryTest.php b/core/modules/views/src/Tests/GlossaryTest.php
index fd97978..65f7bd6 100644
--- a/core/modules/views/src/Tests/GlossaryTest.php
+++ b/core/modules/views/src/Tests/GlossaryTest.php
@@ -87,7 +87,7 @@ public function testGlossaryView() {
 
     // Verify cache tags.
     $this->enablePageCaching();
-    $this->assertPageCacheContextsAndTags(Url::fromRoute('view.glossary.page_1'), ['cache.context.url', 'node_view_grants', 'language', 'user'], [
+    $this->assertPageCacheContextsAndTags(Url::fromRoute('view.glossary.page_1'), ['node_view_grants', 'language', 'url'], [
       'config:views.view.glossary',
       'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
       'node_list',
diff --git a/core/modules/views/src/Tests/RenderCacheIntegrationTest.php b/core/modules/views/src/Tests/RenderCacheIntegrationTest.php
index da94ab4..851d736 100644
--- a/core/modules/views/src/Tests/RenderCacheIntegrationTest.php
+++ b/core/modules/views/src/Tests/RenderCacheIntegrationTest.php
@@ -221,7 +221,7 @@ public function testViewAddCacheMetadata() {
     $view = View::load('test_display');
     $view->save();
 
-    $this->assertEqual(['node_view_grants', 'user', 'language'], $view->getDisplay('default')['cache_metadata']['contexts']);
+    $this->assertEqual(['language', 'node_view_grants'], $view->getDisplay('default')['cache_metadata']['contexts']);
   }
 
 }
diff --git a/core/modules/views/src/Tests/ViewUnitTestBase.php b/core/modules/views/src/Tests/ViewUnitTestBase.php
index 2de7f2b..eaa2694 100644
--- a/core/modules/views/src/Tests/ViewUnitTestBase.php
+++ b/core/modules/views/src/Tests/ViewUnitTestBase.php
@@ -33,11 +33,23 @@
    */
   public static $modules = array('system', 'views', 'views_test_config', 'views_test_data');
 
-  protected function setUp() {
+  /**
+   * {@inheritdoc}
+   *
+   * @param bool $import_test_views
+   *   Should the views specififed on the test class be imported. If you need
+   *   to setup some additional stuff, like fields, you need to call false and
+   *   then call createTestViews for your own.
+   */
+  protected function setUp($import_test_views = TRUE) {
     parent::setUp();
 
     $this->installSchema('system', array('router', 'sequences'));
     $this->setUpFixtures();
+
+    if ($import_test_views) {
+      ViewTestData::createTestViews(get_class($this), array('views_test_config'));
+    }
   }
 
   /**
@@ -46,7 +58,7 @@ protected function setUp() {
    * Because the schema of views_test_data.module is dependent on the test
    * using it, it cannot be enabled normally.
    */
-  protected function setUpFixtures() {
+  protected function setUpFixtures($import_test_views = TRUE) {
     // First install the system module. Many Views have Page displays have menu
     // links, and for those to work, the system menus must already be present.
     $this->installConfig(array('system'));
@@ -70,8 +82,6 @@ protected function setUpFixtures() {
       $query->values($record);
     }
     $query->execute();
-
-    ViewTestData::createTestViews(get_class($this), array('views_test_config'));
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php
index 1563a6d..4fec080 100644
--- a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php
+++ b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheContexts;
 use Drupal\Core\Cache\CacheContextInterface;
 use Drupal\Core\Cache\CalculatedCacheContextInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\DependencyInjection\Container;
 
@@ -108,6 +109,53 @@ protected function getMockContainer() {
     return $container;
   }
 
+  /**
+   * Provides a list of cache context token arrays.
+   *
+   * @return array
+   */
+  public function validateContextsProvider() {
+    return [
+      [[], FALSE],
+      [['foo'], FALSE],
+      [['foo', 'foo.bar'], FALSE],
+      [['foo', 'baz:llama'], FALSE],
+      // Invalid.
+      [[FALSE], 'Cache contexts must be strings, boolean given.'],
+      [[TRUE], 'Cache contexts must be strings, boolean given.'],
+      [['foo', FALSE], 'Cache contexts must be strings, boolean given.'],
+      [[NULL], 'Cache contexts must be strings, NULL given.'],
+      [['foo', NULL], 'Cache contexts must be strings, NULL given.'],
+      [[1337], 'Cache contexts must be strings, integer given.'],
+      [['foo', 1337], 'Cache contexts must be strings, integer given.'],
+      [[3.14], 'Cache contexts must be strings, double given.'],
+      [['foo', 3.14], 'Cache contexts must be strings, double given.'],
+      [[[]], 'Cache contexts must be strings, array given.'],
+      [['foo', []], 'Cache contexts must be strings, array given.'],
+      [['foo', ['bar']], 'Cache contexts must be strings, array given.'],
+      [[new \stdClass()], 'Cache contexts must be strings, object given.'],
+      [['foo', new \stdClass()], 'Cache contexts must be strings, object given.'],
+      // Non-existing.
+      [['foo.bar', 'qux'], '"qux" is not a valid cache context ID.'],
+      [['qux', 'baz'], '"qux" is not a valid cache context ID.'],
+    ];
+  }
+
+  /**
+   * @covers ::validate
+   *
+   * @dataProvider validateContextsProvider
+   */
+  public function testValidateContexts(array $contexts, $expected_exception_message) {
+    $container = new ContainerBuilder();
+    $cache_contexts = new CacheContexts($container, ['foo', 'foo.bar', 'baz']);
+    if ($expected_exception_message !== FALSE) {
+      $this->setExpectedException('LogicException', $expected_exception_message);
+    }
+    // If it doesn't throw an exception, validate() returns NULL.
+    $this->assertNull($cache_contexts->validate($contexts));
+  }
+
 }
 
 /**
diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php
index 261aa80..c2e61a1 100644
--- a/core/tests/Drupal/Tests/Core/Cache/CacheTest.php
+++ b/core/tests/Drupal/Tests/Core/Cache/CacheTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
 
 /**
  * @coversDefaultClass \Drupal\Core\Cache\Cache
@@ -27,6 +28,7 @@ public function validateTagsProvider() {
       [['foo'], FALSE],
       [['foo', 'bar'], FALSE],
       [['foo', 'bar', 'llama:2001988', 'baz', 'llama:14031991'], FALSE],
+      // Invalid.
       [[FALSE], 'Cache tags must be strings, boolean given.'],
       [[TRUE], 'Cache tags must be strings, boolean given.'],
       [['foo', FALSE], 'Cache tags must be strings, boolean given.'],
