diff --git a/core/lib/Drupal/Core/Cache/CacheableMetadata.php b/core/lib/Drupal/Core/Cache/CacheableMetadata.php
index 33d5afb..34d1a74 100644
--- a/core/lib/Drupal/Core/Cache/CacheableMetadata.php
+++ b/core/lib/Drupal/Core/Cache/CacheableMetadata.php
@@ -204,6 +204,8 @@ public function merge(CacheableMetadata $other) {
     else {
       $result->maxAge = Cache::mergeMaxAges($this->maxAge, $other->maxAge);
     }
+
+    assert('$result instanceof \\Drupal\\Core\\Cache\\CacheableMetadata');
     return $result;
   }
 
diff --git a/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php
index b01dc9e..c9a5c53 100644
--- a/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php
+++ b/core/lib/Drupal/Core/Cache/Context/CacheContextsManager.php
@@ -107,6 +107,8 @@ public function getLabels($include_calculated_cache_contexts = FALSE) {
    *   Thrown if any of the context tokens or parameters are not valid.
    */
   public function convertTokensToKeys(array $context_tokens) {
+    assert('\\Drupal\\Component\\Assertion\\Inspector::assertAllStrings($context_tokens)');
+
     $this->validateTokens($context_tokens);
     $cacheable_metadata = new CacheableMetadata();
     $optimized_tokens = $this->optimizeTokens($context_tokens);
diff --git a/core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php b/core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php
index 4b5593f..ff181f4 100644
--- a/core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php
+++ b/core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php
@@ -28,6 +28,7 @@ class ContextCacheKeys extends CacheableMetadata {
    *   The cache context keys.
    */
   public function __construct(array $keys) {
+    assert('Drupal\\Component\\Assertion\\Inspector::assertAllStrings($keys)');
     $this->keys = $keys;
   }
 
diff --git a/core/lib/Drupal/Core/Cache/Context/QueryArgsCacheContext.php b/core/lib/Drupal/Core/Cache/Context/QueryArgsCacheContext.php
index cab1da8..fca0dd1 100644
--- a/core/lib/Drupal/Core/Cache/Context/QueryArgsCacheContext.php
+++ b/core/lib/Drupal/Core/Cache/Context/QueryArgsCacheContext.php
@@ -30,11 +30,11 @@ public static function getLabel() {
    */
   public function getContext($query_arg = NULL) {
     if ($query_arg === NULL) {
-      return $this->requestStack->getCurrentRequest()->getQueryString();
-    }
-    else {
-      return $this->requestStack->getCurrentRequest()->query->get($query_arg);
+      return (string) $this->requestStack->getCurrentRequest()->getQueryString();
     }
+
+    $value = $this->requestStack->getCurrentRequest()->query->get($query_arg, NULL, TRUE);
+    return http_build_query([$query_arg => $value], '', '&');
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Cache/Context/QueryArgsCacheContextTest.php b/core/tests/Drupal/Tests/Core/Cache/Context/QueryArgsCacheContextTest.php
new file mode 100644
index 0000000..059aa6f
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Cache/Context/QueryArgsCacheContextTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Cache\Context\QueryArgsCacheContextTest.
+ */
+
+namespace Drupal\Tests\Core\Cache\Context;
+
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\Cache\Context\QueryArgsCacheContext;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Cache\Context\QueryArgsCacheContext
+ * @group Cache
+ */
+class QueryArgsCacheContextTest extends UnitTestCase {
+
+  /**
+   * @covers ::getContext
+   *
+   * @dataProvider providerTestGetContext
+   */
+  public function testGetContext($uri, array $context_tokens, array $expected_keys) {
+    $request_stack = new RequestStack();
+    $request_stack->push(Request::create($uri));
+
+    $container_prophecy = $this->prophesize('Symfony\Component\DependencyInjection\ContainerInterface');
+    $container_prophecy->get('cache_context.url.query_args')->willReturn(new QueryArgsCacheContext($request_stack));
+
+    $cache_contexts_manager = new CacheContextsManager($container_prophecy->reveal(), ['url.query_args']);
+
+    $this->assertSame($expected_keys, $cache_contexts_manager->convertTokensToKeys($context_tokens)->getKeys());
+  }
+
+  /**
+   * Data provider for testGetContext.
+   *
+   * @return array
+   */
+  public function providerTestGetContext() {
+    return [
+      ['/foo', ['url.query_args'], ['[url.query_args]=']],
+      ['/foo?', ['url.query_args'], ['[url.query_args]=']],
+      ['/foo?a', ['url.query_args'], ['[url.query_args]=a']],
+      ['/foo?a=', ['url.query_args'], ['[url.query_args]=a=']],
+      ['/foo?a=1', ['url.query_args'], ['[url.query_args]=a=1']],
+      ['/foo?b[value]=1&a=2', ['url.query_args'], ['[url.query_args]=a=2&b%5Bvalue%5D=1']],
+      ['/foo', ['url.query_args:a'], ['[url.query_args:a]=']],
+      ['/foo?', ['url.query_args:a'], ['[url.query_args:a]=']],
+      ['/foo?a', ['url.query_args:a'], ['[url.query_args:a]=a=']],
+      ['/foo?a=', ['url.query_args:a'], ['[url.query_args:a]=a=']],
+      ['/foo?a=1', ['url.query_args:a'], ['[url.query_args:a]=a=1']],
+      ['/foo?a=1', ['url.query_args:b'], ['[url.query_args:b]=']],
+      ['/foo?b[value]=1&a=2', ['url.query_args:a'], ['[url.query_args:a]=a=2']],
+      ['/foo?b[value]=1&a=2', ['url.query_args:b'], ['[url.query_args:b]=b%5Bvalue%5D=1']],
+      ['/foo?b[value]=1&a=2', ['url.query_args:a', 'url.query_args:b'], ['[url.query_args:a]=a=2', '[url.query_args:b]=b%5Bvalue%5D=1']],
+      ['/foo?b[value]=1&a=2', ['url.query_args:b[value]'], ['[url.query_args:b[value]]=b%5Bvalue%5D=1']],
+    ];
+  }
+}
