diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php
index f30158333211da1c812d7dac30aeb637af27ae29..04cb7b2ba88d9d294541b05dc823f70293336b9d 100644
--- a/core/lib/Drupal/Component/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Component/Plugin/Context/Context.php
@@ -54,11 +54,15 @@ public function getContextValue() {
     // Support optional contexts.
     if (!isset($this->contextValue)) {
       $definition = $this->getContextDefinition();
-      if ($definition->isRequired()) {
+      $default_value = $definition->getDefaultValue();
+
+      if (!isset($default_value) && $definition->isRequired()) {
         $type = $definition->getDataType();
         throw new ContextException(sprintf("The %s context is required and not present.", $type));
       }
-      return NULL;
+      // Keep the default value here so that subsequent calls don't have to look
+      // it up again.
+      $this->contextValue = $default_value;
     }
     return $this->contextValue;
   }
diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
index c7b69a068b38b4c30b8dbe7166ca042e312ad9d6..1b3c1f45e56306d912d34067379ece05f3115de9 100644
--- a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
@@ -109,6 +109,24 @@ public function isRequired();
    */
   public function setRequired($required = TRUE);
 
+  /**
+   * Provides the default value for this context definition.
+   *
+   * @return mixed
+   *   The default value or NULL if no default value is set.
+   */
+  public function getDefaultValue();
+
+  /**
+   * Sets the default data value.
+   *
+   * @param mixed $default_value
+   *   The default value to be set or NULL to remove any default value.
+   *
+   * @return $this
+   */
+  public function setDefaultValue($default_value);
+
   /**
    * Returns an array of validation constraints.
    *
diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
index 987bab95af975752031ecc67bc865b1f31451a2a..e820f0c3655c369dac468324c946ea79a877646b 100644
--- a/core/lib/Drupal/Core/Annotation/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
@@ -50,6 +50,16 @@
  *   }
  * @endcode
  *
+ * Specifying a default value for the context definition:
+ * @code
+ *   context = {
+ *     "message" = @ContextDefinition("string",
+ *       label = @Translation("Message"),
+ *       default_value = @Translation("Checkout complete! Thank you for your purchase.")
+ *     )
+ *   }
+ * @endcode
+ *
  * @see annotation
  *
  * @}
@@ -85,6 +95,8 @@ class ContextDefinition extends Plugin {
    *   - required: (optional) Whether the context definition is required.
    *   - multiple: (optional) Whether the context definition is multivalue.
    *   - description: (optional) The UI description of this context definition.
+   *   - default_value: (optional) The default value in case the underlying
+   *     value is not set.
    *   - class: (optional) A custom ContextDefinitionInterface class.
    *
    * @throws \Exception
@@ -95,6 +107,7 @@ public function __construct(array $values) {
     $values += array(
       'required' => TRUE,
       'multiple' => FALSE,
+      'default_value' => NULL,
     );
     // Annotation classes extract data from passed annotation classes directly
     // used in the classes they pass to.
@@ -111,7 +124,7 @@ public function __construct(array $values) {
       throw new \Exception('ContextDefinition class must implement \Drupal\Core\Plugin\Context\ContextDefinitionInterface.');
     }
     $class = isset($values['class']) ? $values['class'] : 'Drupal\Core\Plugin\Context\ContextDefinition';
-    $this->definition = new $class($values['value'], $values['label'], $values['required'], $values['multiple'], $values['description']);
+    $this->definition = new $class($values['value'], $values['label'], $values['required'], $values['multiple'], $values['description'], $values['default_value']);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index fb06a1ec485a7a45f4777d26d6e9a3e5366c2617..9835dd7a6be4b1c526a0f471e421782ac1660bf8 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -40,11 +40,18 @@ class Context extends ComponentContext implements ContextInterface {
   public function getContextValue() {
     if (!isset($this->contextData)) {
       $definition = $this->getContextDefinition();
-      if ($definition->isRequired()) {
+      $default_value = $definition->getDefaultValue();
+
+      if (isset($default_value)) {
+        // Keep the default value here so that subsequent calls don't have to
+        // look it up again.
+        $this->setContextValue($default_value);
+      }
+      elseif ($definition->isRequired()) {
         $type = $definition->getDataType();
         throw new ContextException(SafeMarkup::format("The @type context is required and not present.", array('@type' => $type)));
       }
-      return NULL;
+      return $default_value;
     }
     return $this->getTypedDataManager()->getCanonicalRepresentation($this->contextData);
   }
@@ -72,6 +79,15 @@ public function getConstraints() {
    * {@inheritdoc}
    */
   public function getContextData() {
+    if (!isset($this->contextData)) {
+      $definition = $this->getContextDefinition();
+      $default_value = $definition->getDefaultValue();
+      if (isset($default_value)) {
+        // Store the default value so that subsequent calls don't have to look
+        // it up again.
+        $this->contextData = $this->getTypedDataManager()->create($definition->getDataDefinition(), $default_value);
+      }
+    }
     return $this->contextData;
   }
 
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
index b6d16227a837b6c436da7271c11b8158dc2721e7..34ad3621bdde69332518d22b9ec0af589a2dc6ca 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
@@ -56,6 +56,13 @@ class ContextDefinition implements ContextDefinitionInterface {
    */
   protected $isRequired = TRUE;
 
+  /**
+   * The default value.
+   *
+   * @var mixed
+   */
+  protected $defaultValue;
+
   /**
    * An array of constraints.
    *
@@ -90,15 +97,18 @@ public static function create($data_type = 'any') {
    *   Whether the context definition is required.
    * @param bool $multiple
    *   Whether the context definition is multivalue.
-   * @param mixed string|null $description
+   * @param string|null $description
    *   The description of this context definition for the UI.
+   * @param mixed $default_value
+   *   The default value of this definition.
    */
-  public function __construct($data_type = 'any', $label = NULL, $required = TRUE, $multiple = FALSE, $description = NULL) {
+  public function __construct($data_type = 'any', $label = NULL, $required = TRUE, $multiple = FALSE, $description = NULL, $default_value = NULL) {
     $this->dataType = $data_type;
     $this->label = $label;
     $this->isRequired = $required;
     $this->isMultiple = $multiple;
     $this->description = $description;
+    $this->defaultValue = $default_value;
   }
 
   /**
@@ -176,6 +186,21 @@ public function setRequired($required = TRUE) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultValue() {
+    return $this->defaultValue;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setDefaultValue($default_value) {
+    $this->defaultValue = $default_value;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php b/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php
index 77c78a771e503035e0e635fab022350ee3e2a006..c453b6bd6f2993e23ae6de1f58e1cc3917b8318f 100644
--- a/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php
+++ b/core/tests/Drupal/Tests/Component/Plugin/Context/ContextTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests\Component\Plugin\Context;
 
+use Drupal\Component\Plugin\Context\Context;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -86,4 +87,20 @@ public function testGetContextValue($expected, $context_value, $is_required, $da
     }
   }
 
+  /**
+   * @covers ::getContextValue
+   */
+  public function testDefaultValue() {
+    $mock_definition = $this->getMockBuilder('Drupal\Component\Plugin\Context\ContextDefinitionInterface')
+      ->setMethods(array('getDefaultValue'))
+      ->getMockForAbstractClass();
+
+    $mock_definition->expects($this->once())
+      ->method('getDefaultValue')
+      ->willReturn('test');
+
+    $context = new Context($mock_definition);
+    $this->assertEquals('test', $context->getContextValue());
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php
index 57db699c18426299a156bfab45402339666e6e12..1a871bb8489a00f53c21bd67b53905d2f18cfeaf 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests\Core\Plugin\Context;
 
+use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -205,4 +206,15 @@ public function testGetConstraint($expected, $constraint_array, $constraint) {
     $this->assertEquals($expected, $mock_context_definition->getConstraint($constraint));
   }
 
+  /**
+   * @covers ::getDefaultValue
+   * @covers ::setDefaultValue
+   */
+  public function testDefaultValue() {
+    $context_definition = new ContextDefinition();
+    $this->assertNull($context_definition->getDefaultValue());
+    $context_definition->setDefaultValue('test');
+    $this->assertSame('test', $context_definition->getDefaultValue());
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..97702c7ccd8ab9a55c28a76f017dcf399d8bf393
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextTest.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Plugin\Context\ContextTest.
+ */
+
+namespace Drupal\Tests\Core\Plugin\Context;
+
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Plugin\Context\Context
+ * @group Plugin
+ */
+class ContextTest extends UnitTestCase {
+
+  /**
+   * The mocked context definition object.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $contextDefinition;
+
+  /**
+   * The mocked Typed Data manager.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataManager|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $typedDataManager;
+
+  /**
+   * The mocked Typed Data object.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $typedData;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $mock_data_definition = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface');
+
+    $this->contextDefinition = $this->getMockBuilder('Drupal\Core\Plugin\Context\ContextDefinitionInterface')
+      ->setMethods(array('getDefaultValue', 'getDataDefinition'))
+      ->getMockForAbstractClass();
+
+    $this->contextDefinition->expects($this->once())
+      ->method('getDefaultValue')
+      ->willReturn('test');
+
+    $this->contextDefinition->expects($this->once())
+      ->method('getDataDefinition')
+      ->willReturn($mock_data_definition);
+
+    $this->typedData = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
+
+    $this->typedDataManager = $this->getMockBuilder('Drupal\Core\TypedData\TypedDataManager')
+      ->disableOriginalConstructor()
+      ->setMethods(array('create'))
+      ->getMock();
+
+    $this->typedDataManager->expects($this->once())
+      ->method('create')
+      ->with($mock_data_definition, 'test')
+      ->willReturn($this->typedData);
+  }
+
+  /**
+   * @covers ::getContextValue
+   */
+  public function testDefaultValue() {
+    $context = new Context($this->contextDefinition);
+    $context->setTypedDataManager($this->typedDataManager);
+    $this->assertEquals('test', $context->getContextValue());
+  }
+
+  /**
+   * @covers ::getContextData
+   */
+  public function testDefaultDataValue() {
+    $context = new Context($this->contextDefinition);
+    $context->setTypedDataManager($this->typedDataManager);
+    $this->assertEquals($this->typedData, $context->getContextData());
+  }
+
+}