diff --git a/page_manager.services.yml b/page_manager.services.yml
index f4b5c01..eaa0791 100644
--- a/page_manager.services.yml
+++ b/page_manager.services.yml
@@ -16,8 +16,13 @@ services:
       - { name: 'event_subscriber' }
   page_manager.page_manager_routes:
     class: Drupal\page_manager\Routing\PageManagerRoutes
-    arguments: ['@entity.manager']
+    arguments: ['@entity.manager', '@cache_tags.invalidator']
     tags:
       - { name: 'event_subscriber' }
   page_manager.executable_factory:
     class: Drupal\page_manager\PageExecutableFactory
+  page_manager.route_name_response_subscriber:
+    class: Drupal\page_manager\EventSubscriber\RouteNameResponseSubscriber
+    tags:
+      - { name: event_subscriber }
+    arguments: ['@current_route_match']
diff --git a/src/EventSubscriber/RouteNameResponseSubscriber.php b/src/EventSubscriber/RouteNameResponseSubscriber.php
new file mode 100644
index 0000000..7adf876
--- /dev/null
+++ b/src/EventSubscriber/RouteNameResponseSubscriber.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\EventSubscriber\RouteNameResponseSubscriber.
+ */
+
+namespace Drupal\page_manager\EventSubscriber;
+
+use Drupal\Core\Cache\CacheableResponseInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * @todo.
+ */
+class RouteNameResponseSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new RouteNameResponseSubscriber.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
+   */
+  public function __construct(RouteMatchInterface $route_match) {
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * @todo.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
+   *   The event to process.
+   */
+  public function onRespond(FilterResponseEvent $event) {
+    $response = $event->getResponse();
+    if ($response instanceof CacheableResponseInterface) {
+      $cacheability_metadata = $response->getCacheableMetadata();
+      $cacheability_metadata->addCacheTags(['route_name:' . $this->routeMatch->getRouteName()]);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    // Run before finish_response_subscriber:onRespond.
+    $events[KernelEvents::RESPONSE][] = ['onRespond', 1];
+    return $events;
+  }
+
+}
diff --git a/src/Routing/PageManagerRoutes.php b/src/Routing/PageManagerRoutes.php
index 5890c40..b8356b1 100644
--- a/src/Routing/PageManagerRoutes.php
+++ b/src/Routing/PageManagerRoutes.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\page_manager\Routing;
 
+use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Routing\RouteCompiler;
 use Drupal\Core\Routing\RouteSubscriberBase;
@@ -27,13 +28,23 @@ class PageManagerRoutes extends RouteSubscriberBase {
   protected $entityStorage;
 
   /**
+   * The cache tags invalidator.
+   *
+   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
+   */
+  protected $cacheTagsInvalidator;
+
+  /**
    * Constructs a new PageManagerRoutes.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
+   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
+   *   The cache tags invalidator.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
+  public function __construct(EntityManagerInterface $entity_manager, CacheTagsInvalidatorInterface $cache_tags_invalidator) {
     $this->entityStorage = $entity_manager->getStorage('page');
+    $this->cacheTagsInvalidator = $cache_tags_invalidator;
   }
 
   /**
@@ -77,6 +88,7 @@ protected function alterRoutes(RouteCollection $collection) {
           $route_name = $name;
           // Remove the existing route.
           $collection->remove($route_name);
+          $this->cacheTagsInvalidator->invalidateTags(["route_name:$route_name"]);
           break;
         }
       }
diff --git a/src/Tests/PageNodeSelectionTest.php b/src/Tests/PageNodeSelectionTest.php
index 94b26e0..ef1af53 100644
--- a/src/Tests/PageNodeSelectionTest.php
+++ b/src/Tests/PageNodeSelectionTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\page_manager\Tests;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -46,6 +47,7 @@ public function testAdmin() {
     $this->assertTitle($node1->label() . ' | Drupal');
     $this->drupalGet('node/' . $node2->id());
     $this->assertResponse(200);
+    $this->assertCacheTag('route_name:entity.node.canonical');
     $this->assertText($node2->label());
     $this->assertTitle($node2->label() . ' | Drupal');
 
@@ -56,9 +58,11 @@ public function testAdmin() {
       'path' => 'node/%',
     ];
     $this->drupalPostForm('admin/structure/page_manager/add', $edit, 'Save');
+    Cache::invalidateTags(['route_name:entity.node.canonical']);
     // Their pages should now use the default 404 display variant.
     $this->drupalGet('node/' . $node1->id());
     $this->assertResponse(404);
+    $this->assertCacheTag('route_name:entity.node.canonical');
     $this->assertNoText($node1->label());
     $this->drupalGet('node/' . $node2->id());
     $this->assertResponse(404);
diff --git a/src/Tests/PagePlaceholderTest.php b/src/Tests/PagePlaceholderTest.php
index 65f213d..439e916 100644
--- a/src/Tests/PagePlaceholderTest.php
+++ b/src/Tests/PagePlaceholderTest.php
@@ -37,6 +37,7 @@ public function testPagePlaceHolder() {
     $page_string = 'test-page';
     $this->drupalGet('page-manager-test/' . $page_string);
     $this->assertResponse(200);
+    $this->assertCacheTag('route_name:page_manager_test.page_view');
     $this->assertText('Hello World! Page ' . $page_string);
 
     // Create a new page entity with the same path as in the test module.
@@ -52,6 +53,7 @@ public function testPagePlaceHolder() {
     // Access the page callback again and check that now the text is not there.
     $this->drupalGet('page-manager-test/' . $page_string);
     $this->assertResponse(200);
+    $this->assertCacheTag('route_name:page_manager_test.page_view');
     $this->assertNoText('Hello World! Page ' . $page_string);
   }
 
diff --git a/tests/src/Unit/PageManagerRoutesTest.php b/tests/src/Unit/PageManagerRoutesTest.php
index 42c52eb..0de039b 100644
--- a/tests/src/Unit/PageManagerRoutesTest.php
+++ b/tests/src/Unit/PageManagerRoutesTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests\page_manager\Unit;
 
+use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
 use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Routing\RouteBuildEvent;
@@ -40,6 +41,13 @@ class PageManagerRoutesTest extends UnitTestCase {
   protected $pageStorage;
 
   /**
+   * The cache tags invalidator.
+   *
+   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\Prophecy\Prophecy\ProphecyInterface
+   */
+  protected $cacheTagsInvalidator;
+
+  /**
    * The tested page route subscriber.
    *
    * @var \Drupal\page_manager\Routing\PageManagerRoutes
@@ -57,8 +65,9 @@ protected function setUp() {
     $this->entityManager = $this->prophesize(EntityManagerInterface::class);
     $this->entityManager->getStorage('page')
       ->willReturn($this->pageStorage);
+    $this->cacheTagsInvalidator = $this->prophesize(CacheTagsInvalidatorInterface::class);
 
-    $this->routeSubscriber = new PageManagerRoutes($this->entityManager->reveal());
+    $this->routeSubscriber = new PageManagerRoutes($this->entityManager->reveal(), $this->cacheTagsInvalidator->reveal());
   }
 
   /**
@@ -160,6 +169,7 @@ public function testAlterRoutesWithStatus() {
    * @dataProvider providerTestAlterRoutesOverrideExisting
    */
   public function testAlterRoutesOverrideExisting($page_path, $existing_route_path) {
+    $route_name = 'test_route';
     // Set up a page with the same path as an existing route.
     $page = $this->prophesize(PageInterface::class);
     $page->status()
@@ -176,8 +186,10 @@ public function testAlterRoutesOverrideExisting($page_path, $existing_route_path
       ->willReturn(['page1' => $page->reveal()])
       ->shouldBeCalledTimes(1);
 
+    $this->cacheTagsInvalidator->invalidateTags(["route_name:$route_name"])->shouldBeCalledTimes(1);
+
     $collection = new RouteCollection();
-    $collection->add('test_route', new Route($existing_route_path, [], [], ['parameters' => ['foo' => 'bar']]));
+    $collection->add($route_name, new Route($existing_route_path, [], [], ['parameters' => ['foo' => 'bar']]));
     $route_event = new RouteBuildEvent($collection);
     $this->routeSubscriber->onAlterRoutes($route_event);
 
@@ -185,7 +197,7 @@ public function testAlterRoutesOverrideExisting($page_path, $existing_route_path
     $this->assertSame(1, $collection->count());
     $this->assertNull($collection->get('page_manager.page_view_page1'));
 
-    $route = $collection->get('test_route');
+    $route = $collection->get($route_name);
     $expected_defaults = [
       '_entity_view' => 'page_manager_page',
       'page_manager_page' => 'page1',
diff --git a/tests/src/Unit/RouteNameResponseSubscriberTest.php b/tests/src/Unit/RouteNameResponseSubscriberTest.php
new file mode 100644
index 0000000..593de44
--- /dev/null
+++ b/tests/src/Unit/RouteNameResponseSubscriberTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\page_manager\Unit\RouteNameResponseSubscriberTest.
+ */
+
+namespace Drupal\Tests\page_manager\Unit;
+
+use Drupal\Core\Cache\CacheableResponse;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\page_manager\EventSubscriber\RouteNameResponseSubscriber;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * @coversDefaultClass \Drupal\page_manager\EventSubscriber\RouteNameResponseSubscriber
+ * @group PageManager
+ */
+class RouteNameResponseSubscriberTest extends UnitTestCase {
+
+  /**
+   * @covers ::onRespond
+   */
+  public function testOnRespondCacheable() {
+    $response = new CacheableResponse('');
+    $event = $this->buildEvent($response);
+
+    $route_name = 'the_route_name';
+    $route_match = $this->prophesize(RouteMatchInterface::class);
+    $route_match->getRouteName()->willReturn($route_name);
+
+    $subscriber = new RouteNameResponseSubscriber($route_match->reveal());
+    $subscriber->onRespond($event);
+
+    $expected = ["route_name:$route_name"];
+    $this->assertSame($expected, $response->getCacheableMetadata()->getCacheTags());
+  }
+
+  /**
+   * @covers ::onRespond
+   */
+  public function testOnRespondUncacheable() {
+    $response = new Response('');
+    $event = $this->buildEvent($response);
+
+    $route_match = $this->prophesize(RouteMatchInterface::class);
+    $route_match->getRouteName()->shouldNotBeCalled();
+
+    $subscriber = new RouteNameResponseSubscriber($route_match->reveal());
+    $subscriber->onRespond($event);
+  }
+
+  protected function buildEvent(Response $response) {
+    $kernel = $this->prophesize(HttpKernelInterface::class);
+    $request = Request::create('');
+    return new FilterResponseEvent($kernel->reveal(), $request, HttpKernelInterface::SUB_REQUEST, $response);
+  }
+
+}
