diff --git a/core/modules/views/lib/Drupal/views/Entity/View.php b/core/modules/views/lib/Drupal/views/Entity/View.php
index e9f9365..b5e5f94 100644
--- a/core/modules/views/lib/Drupal/views/Entity/View.php
+++ b/core/modules/views/lib/Drupal/views/Entity/View.php
@@ -309,7 +309,7 @@ public function postSave(EntityStorageControllerInterface $storage_controller, $
     // @todo Remove if views implements a view_builder controller.
     $id = $this->id();
     Cache::deleteTags(array('view' => array($id => $id)));
-    views_invalidate_cache();
+    Views::invalidateCache();
   }
 
   /**
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php
index 5a284d8..002e1c7 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayTest.php
@@ -251,8 +251,7 @@ public function testInvalidDisplayPlugins() {
     $this->assertText(t('The plugin (invalid) did not specify an instance class.'));
 
     // Rebuild the router, and ensure that the path is not accessible anymore.
-    views_invalidate_cache();
-    \Drupal::service('router.builder')->rebuildIfNeeded();
+    Views::invalidateCache();
 
     $this->drupalGet('test_display_invalid');
     $this->assertResponse(404);
diff --git a/core/modules/views/lib/Drupal/views/Views.php b/core/modules/views/lib/Drupal/views/Views.php
index 40c5cd1..d2b5aaf 100644
--- a/core/modules/views/lib/Drupal/views/Views.php
+++ b/core/modules/views/lib/Drupal/views/Views.php
@@ -8,6 +8,7 @@
 namespace Drupal\views;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Cache\Cache;
 
 /**
  * Static service container wrapper for views.
@@ -76,6 +77,31 @@ public static function handlerManager($type) {
   }
 
   /**
+   * Invalidates the views cache, forcing a rebuild on the next grab of table
+   * data.
+   */
+  public static function invalidateCache() {
+    // Clear the page and block cache and Views' info cache entries.
+    Cache::invalidateTags(array('content' => TRUE, 'views_info' => TRUE));
+
+    // Set the menu as needed to be rebuilt.
+    \Drupal::service('router.builder')->setRebuildNeeded();
+
+    $module_handler = \Drupal::moduleHandler();
+
+    // Reset the RouteSubscriber from views.
+    \Drupal::getContainer()->get('views.route_subscriber')->reset();
+
+    // Invalidate the block cache to update views block derivatives.
+    if ($module_handler->moduleExists('block')) {
+      \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
+    }
+
+    // Allow modules to respond to the Views cache being cleared.
+    $module_handler->invokeAll('views_invalidate_cache');
+  }
+
+  /**
    * Loads a view from configuration and returns its executable object.
    *
    * @param string $id
diff --git a/core/modules/views/lib/Drupal/views/ViewsData.php b/core/modules/views/lib/Drupal/views/ViewsData.php
index a1e2da4..1aa8dac 100644
--- a/core/modules/views/lib/Drupal/views/ViewsData.php
+++ b/core/modules/views/lib/Drupal/views/ViewsData.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -135,7 +136,7 @@ public function get($key = NULL) {
             $this->storage[$key] = array();
           }
           // Create a cache entry for the requested table.
-          $this->cacheSet($cid, $this->storage[$key]);
+          $this->cacheSet($cid, $this->storage[$key], $key);
         }
       }
 
@@ -176,8 +177,8 @@ protected function cacheGet($cid) {
    * @param mixed $data
    *   The data that will be cached.
    */
-  protected function cacheSet($cid, $data) {
-    return $this->cacheBackend->set($this->prepareCid($cid), $data);
+  protected function cacheSet($cid, $data, $key = NULL) {
+    return $this->cacheBackend->set($this->prepareCid($cid), $data, Cache::PERMANENT, $this->getCacheTags($key));
   }
 
   /**
@@ -194,6 +195,22 @@ protected function prepareCid($cid) {
   }
 
   /**
+   * Gets an array of cache tags.
+   *
+   * @return array
+   *   An array of cache tags.
+   */
+  protected function getCacheTags($key = NULL) {
+    $tags = array('views_data' => TRUE);
+
+    if (isset($key)) {
+      $tags["views_data:$key"] = TRUE;
+    }
+
+    return $tags;
+  }
+
+  /**
    * Gets all data invoked by hook_views_data().
    *
    * This is requested from the cache before being rebuilt.
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 5c2c166..fa7b300 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -525,46 +525,23 @@ function views_language_list($field = 'name', $flags = Language::STATE_ALL) {
  * Implements hook_ENTITY_TYPE_update() for 'field_instance_config'.
  */
 function views_field_instance_config_update(FieldInstanceConfigInterface $field_instance) {
-  // @todo: Is this necessary? Use cache tags to only delete Views' cache data?
-  \Drupal::cache('data')->deleteAll();
-  \Drupal::cache('render')->deleteAll();
+  Cache::invalidateTags(array('views_data' => TRUE));
 }
 
 /**
  * Implements hook_ENTITY_TYPE_delete() for 'field_instance_config'.
  */
 function views_field_instance_config_delete(FieldInstanceConfigInterface $field_instance) {
-  // @todo: Is this necessary? Use cache tags to only delete Views' cache data?
-  \Drupal::cache('data')->deleteAll();
-  \Drupal::cache('render')->deleteAll();
+  Cache::invalidateTags(array('views_data' => TRUE));
 }
 
 /**
  * Invalidate the views cache, forcing a rebuild on the next grab of table data.
+ *
+ * @deprecated @todo
  */
 function views_invalidate_cache() {
-  // Clear Views' info cache entries.
-  // @todo: Use cache tags?
-  \Drupal::cache('data')->deleteAll();
-
-  // Clear the page and block cache.
-  Cache::deleteTags(array('content' => TRUE));
-
-  // Set the menu as needed to be rebuilt.
-  \Drupal::service('router.builder')->setRebuildNeeded();
-
-  $module_handler = \Drupal::moduleHandler();
-
-  // Reset the RouteSubscriber from views.
-  \Drupal::getContainer()->get('views.route_subscriber')->reset();
-
-  // Invalidate the block cache to update views block derivatives.
-  if ($module_handler->moduleExists('block')) {
-    \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
-  }
-
-  // Allow modules to respond to the Views cache being cleared.
-  $module_handler->invokeAll('views_invalidate_cache');
+  Views::invalidateCache();
 }
 
 /**
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/AdvancedSettingsForm.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/AdvancedSettingsForm.php
index 3ef9653..287c24f 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/AdvancedSettingsForm.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/AdvancedSettingsForm.php
@@ -103,7 +103,7 @@ public function submitForm(array &$form, array &$form_state) {
    * Submission handler to clear the Views cache.
    */
   public function cacheSubmit() {
-    views_invalidate_cache();
+    Views::invalidateCache();
     drupal_set_message($this->t('The cache has been cleared.'));
   }
 
