diff --git a/core/lib/Drupal/Core/Cache/CacheableAjaxResponse.php b/core/lib/Drupal/Core/Cache/CacheableAjaxResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..996e674d8e029d680578632a68234202642c48cc
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/CacheableAjaxResponse.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Drupal\Core\Cache;
+
+use Drupal\Core\Ajax\AjaxResponse;
+
+/**
+ * A AjaxResponse that contains and can expose cacheability metadata.
+ *
+ * Supports Drupal's caching concepts: cache tags for invalidation and cache
+ * contexts for variations.
+ *
+ * @see \Drupal\Core\Cache\Cache
+ * @see \Drupal\Core\Cache\CacheableMetadata
+ * @see \Drupal\Core\Cache\CacheableResponseTrait
+ */
+class CacheableAjaxResponse extends AjaxResponse implements CacheableResponseInterface {
+
+  use CacheableResponseTrait;
+
+}
diff --git a/core/modules/page_cache/tests/src/Functional/PageCacheTest.php b/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
index 5164c57948990d554adbdc8527f43f30edaaa1dd..ef08a5f54bca6ef1acd43fefa3499f88e83ab1e8 100644
--- a/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
+++ b/core/modules/page_cache/tests/src/Functional/PageCacheTest.php
@@ -127,6 +127,7 @@ public function testQueryParameterFormatRequests() {
 
     $accept_header_cache_url = Url::fromRoute('system_test.page_cache_accept_header');
     $accept_header_cache_url_with_json = Url::fromRoute('system_test.page_cache_accept_header', ['_format' => 'json']);
+    $accept_header_cache_url_with_ajax = Url::fromRoute('system_test.page_cache_accept_header', ['_format' => 'json'], ['query' => ['_wrapper_format' => 'drupal_ajax']]);
 
     $this->drupalGet($accept_header_cache_url);
     // Verify that HTML page was not yet cached.
@@ -145,6 +146,15 @@ public function testQueryParameterFormatRequests() {
     $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
     // Verify that the correct JSON response was returned.
     $this->assertSession()->responseContains('{"content":"oh hai this is json"}');
+
+    $this->drupalGet($accept_header_cache_url_with_ajax);
+    // Verify that AJAX response was not yet cached.
+    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
+    $this->drupalGet($accept_header_cache_url_with_ajax);
+    // Verify that AJAX response was cached.
+    $this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
+    // Verify that the correct AJAX response was returned.
+    $this->assertSession()->responseContains('{"content":"oh hai this is ajax"}');
   }
 
   /**
diff --git a/core/modules/system/tests/modules/system_test/src/Controller/PageCacheAcceptHeaderController.php b/core/modules/system/tests/modules/system_test/src/Controller/PageCacheAcceptHeaderController.php
index 7401f814000cab86a5bac58a4814dd326489fd6d..07418c65a67a02179f582c5a9cbdf53075b5d9ed 100644
--- a/core/modules/system/tests/modules/system_test/src/Controller/PageCacheAcceptHeaderController.php
+++ b/core/modules/system/tests/modules/system_test/src/Controller/PageCacheAcceptHeaderController.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\system_test\Controller;
 
+use Drupal\Core\Cache\CacheableAjaxResponse;
 use Drupal\Core\Cache\CacheableJsonResponse;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Cache\CacheableResponse;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -20,12 +22,17 @@ class PageCacheAcceptHeaderController {
    * @return mixed
    */
   public function content(Request $request) {
-    if ($request->getRequestFormat() === 'json') {
-      return new CacheableJsonResponse(['content' => 'oh hai this is json']);
+    if ($request->getRequestFormat() === 'json' && $request->query->get('_wrapper_format') === 'drupal_ajax') {
+      $response = new CacheableAjaxResponse(['content' => 'oh hai this is ajax']);
+    }
+    elseif ($request->getRequestFormat() === 'json') {
+      $response = new CacheableJsonResponse(['content' => 'oh hai this is json']);
     }
     else {
-      return new CacheableResponse("<p>oh hai this is html.</p>");
+      $response = new CacheableResponse("<p>oh hai this is html.</p>");
     }
+    $response->addCacheableDependency((new CacheableMetadata())->addCacheContexts(['url.query_args:_wrapper_format']));
+    return $response;
   }
 
 }