diff --git a/core/core.services.yml b/core/core.services.yml
index 1ee07fe..e7d818b 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -318,9 +318,11 @@ services:
     arguments: ['@config.storage', 'config/schema']
   config.typed:
     class: Drupal\Core\Config\TypedConfigManager
-    arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler']
+    arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler', '@class_resolver']
     tags:
       - { name: plugin_manager_cache_clear }
+    calls:
+      - [setValidationConstraintManager, ['@validation.constraint']]
   context.handler:
     class: Drupal\Core\Plugin\Context\ContextHandler
     arguments: ['@typed_data_manager']
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index 2f4b58f..44af54d 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Config\Schema;
 
+use Drupal\Core\TypedData\ComplexDataInterface;
+
 /**
  * Defines a mapping configuration element.
  *
@@ -15,7 +17,7 @@
  * Read https://www.drupal.org/node/1905070 for more details about configuration
  * schema, types and type resolution.
  */
-class Mapping extends ArrayElement {
+class Mapping extends ArrayElement implements ComplexDataInterface {
 
   /**
    * {@inheritdoc}
@@ -26,4 +28,24 @@ protected function getElementDefinition($key) {
     return $this->buildDataDefinition($definition, $value, $key);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function set($property_name, $value, $notify = TRUE) {
+    $this->value[$property_name] = $value;
+    // @todo notify?
+    return $this;
+  }
+
+  public function getProperties($include_computed = FALSE) {
+    $properties = array();
+    foreach (array_keys($this->value) as $name) {
+      $definition = $this->getElementDefinition($name);
+      if ($include_computed || !$definition->isComputed()) {
+        $properties[$name] = $this->get($name);
+      }
+    }
+    return $properties;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php
index e03427e..476f8aa 100644
--- a/core/lib/Drupal/Core/Config/Schema/Sequence.php
+++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Config\Schema;
 
+use Drupal\Core\TypedData\TraversableTypedDataInterface;
+
 /**
  * Defines a configuration element of type Sequence.
  *
@@ -11,7 +13,7 @@
  * Read https://www.drupal.org/node/1905070 for more details about configuration
  * schema, types and type resolution.
  */
-class Sequence extends ArrayElement {
+class Sequence extends ArrayElement implements TraversableTypedDataInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index 8e3ea45..c932904 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
 use Drupal\Core\Config\Schema\ConfigSchemaDiscovery;
+use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\TypedData\TypedDataManager;
 
@@ -44,13 +45,18 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
    *   The storage object to use for reading schema data
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
    *   The cache backend to use for caching the definitions.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
+   *   The class resolver.
    */
-  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler) {
+  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ClassResolverInterface $class_resolver) {
     $this->configStorage = $configStorage;
     $this->schemaStorage = $schemaStorage;
     $this->setCacheBackend($cache, 'typed_config_definitions');
     $this->alterInfo('config_schema_info');
     $this->moduleHandler = $module_handler;
+    $this->classResolver = $class_resolver;
   }
 
   /**
@@ -179,6 +185,7 @@ protected function getDefinitionWithReplacements($base_plugin_id, array $replace
     $definition += array(
       'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
       'type' => $type,
+      'unwrap_for_canonical_representation' => TRUE,
     );
     return $definition;
   }
diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
index 594f31d..f2600c7 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -576,16 +576,6 @@ protected function getFieldItemClass() {
   /**
    * {@inheritdoc}
    */
-  public function __sleep() {
-    // Do not serialize the statically cached property definitions.
-    $vars = get_object_vars($this);
-    unset($vars['propertyDefinitions']);
-    return array_keys($vars);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getTargetEntityTypeId() {
     return isset($this->definition['entity_type']) ? $this->definition['entity_type'] : NULL;
   }
diff --git a/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php
index 0acdba4..95ba817 100644
--- a/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php
+++ b/core/lib/Drupal/Core/TypedData/ComplexDataDefinitionBase.php
@@ -36,14 +36,4 @@ public function getMainPropertyName() {
     return NULL;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function __sleep() {
-    // Do not serialize the cached property definitions.
-    $vars = get_object_vars($this);
-    unset($vars['propertyDefinitions']);
-    return array_keys($vars);
-  }
-
 }
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinition.php b/core/lib/Drupal/Core/TypedData/DataDefinition.php
index d0878ed..866beb3 100644
--- a/core/lib/Drupal/Core/TypedData/DataDefinition.php
+++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php
@@ -2,11 +2,16 @@
 
 namespace Drupal\Core\TypedData;
 
+use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+
 /**
  * A typed data definition class for defining data based on defined data types.
  */
 class DataDefinition implements DataDefinitionInterface, \ArrayAccess {
 
+  use DependencySerializationTrait;
+  use TypedDataTrait;
+
   /**
    * The array holding values for all definition keys.
    *
@@ -258,7 +263,7 @@ public function setSetting($setting_name, $value) {
    */
   public function getConstraints() {
     $constraints = isset($this->definition['constraints']) ? $this->definition['constraints'] : array();
-    $constraints += \Drupal::typedDataManager()->getDefaultConstraints($this);
+    $constraints += $this->getTypedDataManager()->getDefaultConstraints($this);
     return $constraints;
   }
 
@@ -340,4 +345,14 @@ public function toArray() {
     return $this->definition;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function __sleep() {
+    // Do not serialize the statically cached property definitions.
+    $vars = get_object_vars($this);
+    unset($vars['propertyDefinitions'], $vars['typedDataManager']);
+    return array_keys($vars);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index 4904150..9f59a54 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -117,7 +117,10 @@ public function createDataDefinition($data_type) {
       throw new \InvalidArgumentException("Invalid data type '$data_type' has been given");
     }
     $class = $type_definition['definition_class'];
-    return $class::createFromDataType($data_type);
+    $data_definition = $class::createFromDataType($data_type);
+    $data_definition->setTypedDataManager($this);
+
+    return $data_definition;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
index b765b05..c52c9db 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\ListInterface;
+use Drupal\Core\TypedData\TraversableTypedDataInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedDataManagerInterface;
 use Symfony\Component\Validator\Constraint;
@@ -142,7 +143,10 @@ protected function validateNode(TypedDataInterface $data, $constraints = NULL, $
 
     // If the data is a list or complex data, validate the contained list items
     // or properties. However, do not recurse if the data is empty.
-    if (($data instanceof ListInterface || $data instanceof ComplexDataInterface) && !$data->isEmpty()) {
+    // Note: Most traversable, doesn't have a concept of empty/not empty, but
+    // most implementations, like ListInterface/TypedConfigInterface have.
+    // Therefor first check, that the method exists.
+    if ($data instanceof TraversableTypedDataInterface && (!(method_exists($data, 'isEmpty') && $data->isEmpty()))) {
       foreach ($data as $name => $property) {
         $this->validateNode($property);
       }
diff --git a/core/modules/config/tests/config_test/config/install/config_test.validation.yml b/core/modules/config/tests/config_test/config/install/config_test.validation.yml
new file mode 100644
index 0000000..47b397d
--- /dev/null
+++ b/core/modules/config/tests/config_test/config/install/config_test.validation.yml
@@ -0,0 +1,7 @@
+llama: meh
+cat:
+  type: kitten
+  count: 2
+giraffe:
+  hum1: hum1
+  hum2: hum2
diff --git a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
index 6cad91b..e63c68c 100644
--- a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
+++ b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
@@ -152,3 +152,33 @@ config_test.foo:
 
 config_test.bar:
   type: config_test.foo
+
+config_test.validation:
+  type: config_object
+  label: 'Configuration type'
+  mapping:
+    llama:
+      type: string
+      constraints:
+        Callback:
+          callback: [\Drupal\config_test\ConfigValidation, validateLlama]
+    cat:
+      type: mapping
+      mapping:
+        type:
+          type: string
+          constraints:
+            Callback:
+              callback: [\Drupal\config_test\ConfigValidation, validateCats]
+        count:
+          type: integer
+          constraints:
+            Callback:
+              callback: [\Drupal\config_test\ConfigValidation, validateCatCount]
+    giraffe:
+      type: sequence
+      sequence:
+        type: string
+        constraints:
+          Callback:
+            callback: [\Drupal\config_test\ConfigValidation, validateGiraffes]
diff --git a/core/modules/config/tests/config_test/src/ConfigValidation.php b/core/modules/config/tests/config_test/src/ConfigValidation.php
new file mode 100644
index 0000000..7bf5f70
--- /dev/null
+++ b/core/modules/config/tests/config_test/src/ConfigValidation.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\config_test;
+
+use Symfony\Component\Validator\Context\ExecutionContextInterface;
+
+/**
+ * Provides a collection of validation callbacks for testing purposes.
+ */
+class ConfigValidation {
+
+  /**
+   * Validates a llama.
+   *
+   * @param string $object
+   *   The string to validate.
+   * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
+   *   The validation execution context.
+   */
+  public static function validateLlama($object, ExecutionContextInterface $context) {
+    if ($object !== 'meh') {
+      $context->addViolation('no valid llama');
+    }
+  }
+
+  /**
+   * Validates cats.
+   *
+   * @param string $object
+   *   The string to validate.
+   * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
+   *   The validation execution context.
+   */
+  public static function validateCats($object, ExecutionContextInterface $context) {
+    if (!in_array($object, ['kitten', 'cats', 'nyans'])) {
+      $context->addViolation('no valid cat');
+    }
+  }
+
+  /**
+   * Validates a number.
+   *
+   * @param string $object
+   *   The string to validate.
+   * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
+   *   The validation execution context.
+   */
+  public static function validateCatCount($object, ExecutionContextInterface $context) {
+    if ($object <= 1) {
+      $context->addViolation('no enough cats');
+    }
+  }
+
+  /**
+   * Validates giraffes.
+   *
+   * @param string $object
+   *   The string to validate.
+   * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
+   *   The validation execution context.
+   */
+  public static function validateGiraffes($object, ExecutionContextInterface $context) {
+    if (strpos($object, 'hum') !== 0) {
+      $context->addViolation('Giraffes just hum');
+    }
+  }
+
+}
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index e34d375..15b3a08 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -7,6 +7,8 @@ system.site:
     uuid:
       type: string
       label: 'Site UUID'
+      constraints:
+        NotNull: []
     name:
       type: label
       label: 'Site name'
diff --git a/core/modules/views/tests/src/Kernel/TestViewsTest.php b/core/modules/views/tests/src/Kernel/TestViewsTest.php
index f67b5e8..1dc7cc1 100644
--- a/core/modules/views/tests/src/Kernel/TestViewsTest.php
+++ b/core/modules/views/tests/src/Kernel/TestViewsTest.php
@@ -34,7 +34,8 @@ public function testDefaultConfig() {
       \Drupal::service('config.storage'),
       new TestInstallStorage(InstallStorage::CONFIG_SCHEMA_DIRECTORY),
       \Drupal::service('cache.discovery'),
-      \Drupal::service('module_handler')
+      \Drupal::service('module_handler'),
+      \Drupal::service('class_resolver')
     );
 
     // Create a configuration storage with access to default configuration in
diff --git a/core/tests/Drupal/KernelTests/Config/ConfigValidationTest.php b/core/tests/Drupal/KernelTests/Config/ConfigValidationTest.php
new file mode 100644
index 0000000..af6a4c5
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Config/ConfigValidationTest.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\KernelTests\Config;
+
+use Drupal\KernelTests\KernelTestBase;
+use Symfony\Component\Validator\ConstraintViolationListInterface;
+
+/**
+ * Tests config validation mechanism.
+ *
+ * @group Config
+ */
+class ConfigValidationTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['config_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig('config_test');
+  }
+
+  public function testSimpleConfigValidation() {
+    $config = \Drupal::configFactory()->getEditable('config_test.validation');
+    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager */
+    $typed_config_manager = \Drupal::service('config.typed');
+    /** @var \Drupal\Core\Config\Schema\TypedConfigInterface $typed_config */
+    $typed_config = $typed_config_manager->get('config_test.validation');
+
+    $result = $typed_config->validate();
+    $this->assertInstanceOf(ConstraintViolationListInterface::class, $result);
+    $this->assertEmpty($result);
+
+    // Test constraints on primitive types.
+    $config->set('llama', 'muh');
+    $config->save();
+
+    $typed_config = $typed_config_manager->get('config_test.validation');
+    $result = $typed_config->validate();
+    // Its not a valid llama anymore.
+    $this->assertCount(1, $result);
+    $this->assertEquals('no valid llama', $result->get(0)->getMessage());
+
+    // Test constraints on mapping.
+    $config->set('llama', 'meh');
+    $config->set('cat.type', 'nyans');
+    $config->save();
+
+    $typed_config = $typed_config_manager->get('config_test.validation');
+    $result = $typed_config->validate();
+    $this->assertEmpty($result);
+
+    // Test constrains on nested mapping.
+    $config->set('cat.type', 'miaus');
+    $config->save();
+
+    $typed_config = $typed_config_manager->get('config_test.validation');
+    $result = $typed_config->validate();
+    $this->assertCount(1, $result);
+    $this->assertEquals('no valid cat', $result->get(0)->getMessage());
+
+    // Test constrains on sequences.
+    $config->set('cat.type', 'nyans');
+    $config->set('giraffe', ['muh', 'hum2']);
+    $config->save();
+
+    $typed_config = $typed_config_manager->get('config_test.validation');
+    $result = $typed_config->validate();
+    $this->assertCount(1, $result);
+    $this->assertEquals('Giraffes just hum', $result->get(0)->getMessage());
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
index ae3abdd..dcc7610 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
@@ -43,6 +43,7 @@ function testSchemaMapping() {
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
     $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
 
     // Configuration file without schema will return Undefined as well.
@@ -63,6 +64,8 @@ function testSchemaMapping() {
     $expected['mapping']['testlist'] = array('label' => 'Test list');
     $expected['type'] = 'config_schema_test.someschema';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.');
 
     // Check type detection on elements with undefined types.
@@ -73,6 +76,7 @@ function testSchemaMapping() {
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
     $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.');
     $definition = $config->get('testlist')->getDataDefinition()->toArray();
     $expected = array();
@@ -80,6 +84,7 @@ function testSchemaMapping() {
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
     $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.');
     $definition = $config->get('testnoschema')->getDataDefinition()->toArray();
     $expected = array();
@@ -87,6 +92,8 @@ function testSchemaMapping() {
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
     $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
     $this->assertEqual($definition, $expected, 'Automatic type detected for an undefined integer is undefined.');
 
     // Simple case, straight metadata.
@@ -105,6 +112,8 @@ function testSchemaMapping() {
     $expected['mapping']['_core']['type'] = '_core_config_info';
     $expected['type'] = 'system.maintenance';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
 
     // Mixed schema with ignore elements.
@@ -135,6 +144,8 @@ function testSchemaMapping() {
       'type' => 'integer',
     );
     $expected['type'] = 'config_schema_test.ignore';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
 
     $this->assertEqual($definition, $expected);
 
@@ -145,6 +156,8 @@ function testSchemaMapping() {
     $expected['label'] = 'Irrelevant';
     $expected['class'] = '\Drupal\Core\Config\Schema\Ignore';
     $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
     $this->assertEqual($definition, $expected);
     $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray();
     $expected['label'] = 'Indescribable';
@@ -156,6 +169,7 @@ function testSchemaMapping() {
     $expected['label'] = 'Image style';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['mapping']['name']['type'] = 'string';
     $expected['mapping']['uuid']['type'] = 'string';
     $expected['mapping']['uuid']['label'] = 'UUID';
@@ -179,6 +193,7 @@ function testSchemaMapping() {
     $expected['mapping']['third_party_settings']['sequence']['type'] = '[%parent.%parent.%type].third_party.[%key]';
     $expected['mapping']['_core']['type'] = '_core_config_info';
     $expected['type'] = 'image.style.*';
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
 
     $this->assertEqual($definition, $expected);
 
@@ -189,6 +204,7 @@ function testSchemaMapping() {
     $expected['label'] = 'Image scale';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['mapping']['width']['type'] = 'integer';
     $expected['mapping']['width']['label'] = 'Width';
     $expected['mapping']['height']['type'] = 'integer';
@@ -216,6 +232,7 @@ function testSchemaMapping() {
     $expected['label'] = 'Mapping';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['mapping'] = [
       'integer' => ['type' => 'integer'],
       'string' => ['type' => 'string'],
@@ -237,6 +254,7 @@ function testSchemaMapping() {
     $expected['mapping']['testdescription']['label'] = 'Description';
     $expected['type'] = 'config_schema_test.someschema.somemodule.*.*';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
 
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection');
 
@@ -259,6 +277,7 @@ function testSchemaMappingWithParents() {
       'label' => 'Test item nested one level',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
       'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+      'unwrap_for_canonical_representation' => TRUE,
     );
     $this->assertEqual($definition, $expected);
 
@@ -270,6 +289,7 @@ function testSchemaMappingWithParents() {
       'label' => 'Test item nested two levels',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
       'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+      'unwrap_for_canonical_representation' => TRUE,
     );
     $this->assertEqual($definition, $expected);
 
@@ -281,6 +301,7 @@ function testSchemaMappingWithParents() {
       'label' => 'Test item nested three levels',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\StringData',
       'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+      'unwrap_for_canonical_representation' => TRUE,
     );
     $this->assertEqual($definition, $expected);
   }
@@ -401,6 +422,7 @@ function testSchemaFallback() {
     $expected['label'] = 'Schema wildcard fallback test';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['mapping']['langcode']['type'] = 'string';
     $expected['mapping']['langcode']['label'] = 'Language code';
     $expected['mapping']['_core']['type'] = '_core_config_info';
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
index b61a6dd..dad9c14 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypedDataDefinitionTest.php
@@ -101,8 +101,8 @@ public function testEntities() {
 
     // Test that the definition factory creates the right definitions for all
     // entity data types variants.
-    $this->assertEqual($this->typedDataManager->createDataDefinition('entity'), EntityDataDefinition::create());
-    $this->assertEqual($this->typedDataManager->createDataDefinition('entity:node'), EntityDataDefinition::create('node'));
+    $this->assertEqual(serialize($this->typedDataManager->createDataDefinition('entity')), serialize(EntityDataDefinition::create()));
+    $this->assertEqual(serialize($this->typedDataManager->createDataDefinition('entity:node')), serialize(EntityDataDefinition::create('node')));
 
     // Config entities don't support typed data.
     $entity_definition = EntityDataDefinition::create('node_type');
@@ -123,7 +123,7 @@ public function testEntityReferences() {
     // Test that the definition factory creates the right definition object.
     $reference_definition2 = $this->typedDataManager->createDataDefinition('entity_reference');
     $this->assertTrue($reference_definition2 instanceof DataReferenceDefinitionInterface);
-    $this->assertEqual($reference_definition2, $reference_definition);
+    $this->assertEqual(serialize($reference_definition2), serialize($reference_definition));
   }
 
 }
