diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
index b07f3e6..2c5eea9 100644
--- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -54,7 +54,8 @@ public function get(EntityInterface $entity) {
         unset($entity->{$field_name});
       }
     }
-    return new ResourceResponse($entity);
+
+    return new ResourceResponse($entity, 200, ['X-Drupal-Cache-Tags' => implode(' ', $entity->getCacheTags())]);
   }
 
   /**
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index e205669..b962b32 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\rest;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
@@ -108,6 +109,14 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
       $output = $serializer->serialize($data, $format);
       $response->setContent($output);
       $response->headers->set('Content-Type', $request->getMimeType($format));
+      // Add cache tags, but do not overwrite any that exist already on the
+      // response object.
+      $cache_tags = $this->container->get('config.factory')->get('rest.settings')->getCacheTags();
+      if ($response->headers->has('X-Drupal-Cache-Tags')) {
+        $existing_cache_tags = explode(' ', $response->headers->get('X-Drupal-Cache-Tags'));
+        $cache_tags = Cache::mergeTags($existing_cache_tags, $cache_tags);
+      }
+      $response->headers->set('X-Drupal-Cache-Tags', implode(' ', $cache_tags));
     }
     return $response;
   }
diff --git a/core/modules/rest/src/Tests/PageCacheTest.php b/core/modules/rest/src/Tests/PageCacheTest.php
new file mode 100644
index 0000000..70888a1
--- /dev/null
+++ b/core/modules/rest/src/Tests/PageCacheTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\test\PageCacheTest.
+ */
+
+namespace Drupal\rest\Tests;
+
+use Drupal\Component\Serialization\Json;
+use Drupal\rest\Tests\RESTTestBase;
+
+/**
+ * Tests page caching for REST GET requests.
+ *
+ * @group rest
+ */
+class PageCacheTest extends RESTTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('hal', 'rest', 'entity_test');
+
+  /**
+   * Tests that configuration changes also clear the page cache.
+   */
+  public function testConfigChangePageCache() {
+    $this->enableService('entity:entity_test', 'GET');
+    // Allow anonymous users to issue GET requests.
+    $permissions = $this->entityPermissions('entity_test', 'view');
+    $permissions[] = 'restful get entity:entity_test';
+    user_role_grant_permissions('anonymous', $permissions);
+
+    // Create an entity programmatically.
+    $entity = $this->entityCreate('entity_test');
+    $entity->save();
+    // Read it over the REST API.
+    $this->httpRequest($entity->urlInfo(), 'GET', NULL, $this->defaultMimeType);
+    $this->assertResponse(200, 'HTTP response code is correct.');
+    $this->assertHeader('x-drupal-cache', 'MISS');
+    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('entity_test:1');
+
+    // Read it again, should be page-cached now.
+    $this->httpRequest($entity->urlInfo(), 'GET', NULL, $this->defaultMimeType);
+    $this->assertResponse(200, 'HTTP response code is correct.');
+    $this->assertHeader('x-drupal-cache', 'HIT');
+    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('entity_test:1');
+
+    // Trigger a config save which should clear the page cache, so we should get
+    // a cache miss now for the same request.
+    $this->config('rest.settings')->save();
+    $this->httpRequest($entity->urlInfo(), 'GET', NULL, $this->defaultMimeType);
+    $this->assertResponse(200, 'HTTP response code is correct.');
+    $this->assertHeader('x-drupal-cache', 'MISS');
+    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('entity_test:1');
+  }
+
+}
diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php
index e8e1080..ff382d5 100644
--- a/core/modules/rest/src/Tests/RESTTestBase.php
+++ b/core/modules/rest/src/Tests/RESTTestBase.php
@@ -154,12 +154,15 @@ protected function httpRequest($url, $method, $body = NULL, $mime_type = NULL) {
     }
 
     $response = $this->curlExec($curl_options);
+
+    // Ensure that any changes to variables in the other thread are picked up.
+    $this->refreshVariables();
+
     $headers = $this->drupalGetHeaders();
-    $headers = implode("\n", $headers);
 
     $this->verbose($method . ' request to: ' . $url .
       '<hr />Code: ' . curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE) .
-      '<hr />Response headers: ' . $headers .
+      '<hr />Response headers: ' . nl2br(print_r($headers, TRUE)) .
       '<hr />Response body: ' . $response);
 
     return $response;
