diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php
index 51ad1a6..4d6f723 100644
--- a/core/modules/views/src/Entity/View.php
+++ b/core/modules/views/src/Entity/View.php
@@ -330,8 +330,12 @@ protected function addCacheMetadata() {
   public function postSave(EntityStorageInterface $storage, $update = TRUE) {
     parent::postSave($storage, $update);
 
-    // @todo Remove if views implements a view_builder controller.
-    views_invalidate_cache();
+    Views::invalidateCache();
+
+    $executable = $this->getExecutable();
+    foreach ($executable->displayHandlers as $display_id => $display_handler) {
+      $display_handler->postSaveView(!empty($this->original) ? $this->original->getDisplay($display_id) : []);
+    }
 
     // Rebuild the router if this is a new view, or it's status changed.
     if (!isset($this->original) || ($this->status() != $this->original->status())) {
diff --git a/core/modules/views/src/Plugin/views/display/Block.php b/core/modules/views/src/Plugin/views/display/Block.php
index 9de84ef..4deac68 100644
--- a/core/modules/views/src/Plugin/views/display/Block.php
+++ b/core/modules/views/src/Plugin/views/display/Block.php
@@ -372,4 +372,17 @@ public function remove() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSaveView(array $original_display) {
+    parent::postSaveView($original_display);
+
+    // Invalidate the block cache to update views block derivatives.
+    if (\Drupal::moduleHandler()->moduleExists('block')) {
+      \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
+    }
+  }
+
+
 }
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 5a4bda2..03cb33c 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -2617,6 +2617,16 @@ protected function isBaseTableTranslatable() {
     }
     return FALSE;
   }
+
+  /**
+   * Act on saving a view.
+   *
+   * @param array $orginal_display
+   *   The display settings, of the original entity empty in case of a new view.
+   */
+  public function postSaveView(array $orginal_display) {
+  }
+
 }
 
 /**
diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php
index 27905b8..592c6af 100644
--- a/core/modules/views/src/Plugin/views/display/Page.php
+++ b/core/modules/views/src/Plugin/views/display/Page.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\views\Views;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -487,4 +488,37 @@ public function calculateDependencies() {
     return $dependencies;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSaveView(array $original_display) {
+    parent::postSaveView($original_display);
+
+    // An empty original display means a new view, we need a router rebuild.
+    $route_rebuild = empty($original_display);
+
+    $this->display += ['display_options' => []];
+    $this->display['display_options'] += [
+      'menu' => [],
+      'tab_options' => [],
+    ];
+
+    $original_display += ['display_options' => []];
+    $original_display['display_options'] += [
+      'menu' => [],
+      'tab_options' => [],
+    ];
+
+    if ($this->display['display_options']['menu'] != $original_display['display_options']['menu']) {
+      $route_rebuild = TRUE;
+    }
+    if ($this->display['display_options']['tab_options'] != $original_display['display_options']['tab_options']) {
+      $route_rebuild = TRUE;
+    }
+
+    if ($route_rebuild) {
+      Views::routeRebuildNeeded();
+    }
+  }
+
 }
diff --git a/core/modules/views/src/Plugin/views/display/PathPluginBase.php b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
index 415b704..0ca1429 100644
--- a/core/modules/views/src/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
@@ -512,4 +512,51 @@ public function getAlteredRouteNames() {
     return $this->state->get('views.view_route_names') ?: array();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSaveView(array $original_display) {
+    parent::postSaveView($original_display);
+
+    // An empty original display means a new view, we need a router rebuild.
+    $route_rebuild = empty($original_display);
+
+    $this->display += ['display_options' => []];
+    $this->display['display_options'] += [
+      'path' => '',
+      'route_name' => '',
+      'arguments' => [],
+      'access' => [],
+    ];
+
+    $original_display += ['display_options' => []];
+    $original_display['display_options'] += [
+      'path' => '',
+      'route_name' => '',
+      'arguments' => [],
+      'access' => [],
+    ];
+
+    if ($this->display['display_options']['path'] != $original_display['display_options']['path']) {
+      $route_rebuild = TRUE;
+    }
+
+    if ($this->display['display_options']['route_name'] != $original_display['display_options']['route_name']) {
+      $route_rebuild = TRUE;
+    }
+
+    if ($this->display['display_options']['arguments'] != $original_display['display_options']['arguments']) {
+      $route_rebuild = TRUE;
+    }
+
+    if ($this->display['display_options']['access'] != $original_display['display_options']['access']) {
+      $route_rebuild = TRUE;
+    }
+
+    if ($route_rebuild) {
+      Views::routeRebuildNeeded();
+    }
+  }
+
+
 }
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index 11dce89..20d5979 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -214,7 +214,7 @@ class ViewExecutable implements \Serializable {
    * An array containing Drupal\views\Plugin\views\display\DisplayPluginBase
    * objects.
    *
-   * @var \Drupal\views\DisplayPluginCollection
+   * @var \Drupal\views\DisplayPluginCollection|\Drupal\views\Plugin\views\display\DisplayPluginBase[]
    */
   public $displayHandlers;
 
diff --git a/core/modules/views/src/Views.php b/core/modules/views/src/Views.php
index 525177f..b2dd31e 100644
--- a/core/modules/views/src/Views.php
+++ b/core/modules/views/src/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.
@@ -534,4 +535,25 @@ protected static function t($string, array $args = array(), array $options = arr
     return static::$translationManager->translate($string, $args, $options);
   }
 
+  /**
+   * Forces a router rebuild for views.
+   */
+  public static function routeRebuildNeeded() {
+    // Set the router as needed to be rebuilt.
+    \Drupal::service('router.builder')->setRebuildNeeded();
+
+    // Reset the RouteSubscriber from views.
+    \Drupal::getContainer()->get('views.route_subscriber')->reset();
+  }
+
+  /**
+   * Invalidate the views cache, forcing a rebuild on the next grab of table data.
+   */
+  public static function invalidateCache() {
+    Cache::invalidateTags(['views_data']);
+    $module_handler = \Drupal::moduleHandler();
+    // Allow modules to respond to the Views cache being cleared.
+    $module_handler->invokeAll('views_invalidate_cache');
+  }
+
 }
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 23fd877..305da7c 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -483,21 +483,7 @@ function views_field_config_delete(FieldConfigInterface $field) {
  * Invalidate the views cache, forcing a rebuild on the next grab of table data.
  */
 function views_invalidate_cache() {
-  // 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();
 }
 
 /**
