diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 0c9ad70569adde8e914aa466da7ea41493f0c772..41332e3eea03d4aca6ab07378182fc44ff866809 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -269,6 +269,11 @@ config_entity:
     dependencies:
       type: config_dependencies
       label: 'Dependencies'
+    third_party_settings:
+      type: sequence
+      label: 'Third party settings'
+      sequence:
+        - type: '[%parent.%parent.%type].third_party.[%key]'
 
 block_settings:
   type: mapping
@@ -393,11 +398,6 @@ field_config_base:
       label: 'Default value callback'
     settings:
       type: field.field_settings.[%parent.field_type]
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: field_config.third_party.[%key]
     field_type:
       type: string
       label: 'Field type'
diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index ee3d5d78285dd07f1c4f1c3a8eb4a1a2bc65ce15..de9530d3865512979e3779c8e1b57c9c8a62175b 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -93,11 +93,6 @@ core.entity_view_display.*.*.*:
       sequence:
         - type: boolean
           label: 'Value'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: entity_view_display.third_party.[%key]
 
 # Overview configuration information for form mode displays.
 core.entity_form_display.*.*.*:
@@ -146,11 +141,6 @@ core.entity_form_display.*.*.*:
       sequence:
         - type: boolean
           label: 'Component'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: entity_form_display.third_party.[%key]
 
 # Default schema for entity display field with undefined type.
 field.formatter.settings.*:
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index e3fcaf8856a66ecb6db5234ff9a2ad225eddaf18..7f4a534c8edc9adf152f7cb131679d0ed673d64c 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -220,8 +220,10 @@ public function uninstall($type, $name) {
       if (isset($entity_dependencies[$type]) && in_array($name, $entity_dependencies[$type])) {
         $affected_dependencies[$type] = array($name);
       }
-      // Inform the entity.
-      $entity->onDependencyRemoval($affected_dependencies);
+      // Inform the entity and, if the entity is changed, re-save it.
+      if ($entity->onDependencyRemoval($affected_dependencies)) {
+        $entity->save();
+      }
     }
 
     // Recalculate the dependencies, some config entities may have fixed their
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index 12a45432175718ef194cafbfb53d2837f5e541a3..9c8a5e2b61800b2fb1bd5302a6d7835927a18a6d 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\Core\Config\Entity;
 
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Schema\SchemaIncompleteException;
 use Drupal\Core\Entity\Entity;
 use Drupal\Core\Config\ConfigDuplicateUUIDException;
+use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
@@ -24,7 +24,7 @@
  *
  * @ingroup entity_api
  */
-abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
+abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface, ThirdPartySettingsInterface {
 
   use PluginDependencyTrait {
     addDependency as addDependencyTrait;
@@ -87,6 +87,15 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
    */
   protected $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
 
+  /**
+   * Third party entity settings.
+   *
+   * An array of key/value pairs keyed by provider.
+   *
+   * @var array
+   */
+  protected $third_party_settings = array();
+
   /**
    * Overrides Entity::__construct().
    */
@@ -259,6 +268,9 @@ public function toArray() {
         $properties[$name] = $this->get($name);
       }
     }
+    if (empty($this->third_party_settings)) {
+      unset($properties['third_party_settings']);
+    }
     return $properties;
   }
 
@@ -430,6 +442,13 @@ public function getConfigTarget() {
    * {@inheritdoc}
    */
   public function onDependencyRemoval(array $dependencies) {
+    $changed = FALSE;
+    if (!empty($this->third_party_settings)) {
+      $old_count = count($this->third_party_settings);
+      $this->third_party_settings = array_diff_key($this->third_party_settings, array_flip($dependencies['module']));
+      $changed = $old_count != count($this->third_party_settings);
+    }
+    return $changed;
   }
 
   /**
@@ -452,4 +471,51 @@ protected static function invalidateTagsOnDelete(EntityTypeInterface $entity_typ
     Cache::invalidateTags($entity_type->getListCacheTags());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function setThirdPartySetting($module, $key, $value) {
+    $this->third_party_settings[$module][$key] = $value;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getThirdPartySetting($module, $key, $default = NULL) {
+    if (isset($this->third_party_settings[$module][$key])) {
+      return $this->third_party_settings[$module][$key];
+    }
+    else {
+      return $default;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getThirdPartySettings($module) {
+    return isset($this->third_party_settings[$module]) ? $this->third_party_settings[$module] : array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function unsetThirdPartySetting($module, $key) {
+    unset($this->third_party_settings[$module][$key]);
+    // If the third party is no longer storing any information, completely
+    // remove the array holding the settings for this module.
+    if (empty($this->third_party_settings[$module])) {
+      unset($this->third_party_settings[$module]);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getThirdPartyProviders() {
+    return array_keys($this->third_party_settings);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
index 15347e3e70f0d55f5c640b28c124677776df4332..1db3b422ee260a4bda8ab11eec367cc7ee52c03e 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
@@ -157,10 +157,13 @@ public function calculateDependencies();
    * This method allows configuration entities to remove dependencies instead
    * of being deleted themselves. Configuration entities can use this method to
    * avoid being unnecessarily deleted during an extension uninstallation.
-   * Implementations should save the entity if dependencies have been
-   * successfully removed. For example, entity displays remove references to
-   * widgets and formatters if the plugin that supplies them depends on a
-   * module that is being uninstalled.
+   * For example, entity displays remove references to widgets and formatters if
+   * the plugin that supplies them depends on a module that is being
+   * uninstalled.
+   *
+   * If this method returns TRUE then the entity needs to be re-saved by the
+   * caller for the changes to take effect. Implementations should not save the
+   * entity.
    *
    * @todo https://www.drupal.org/node/2336727 this method is only fired during
    *   extension uninstallation but it could be used during config entity
@@ -170,6 +173,9 @@ public function calculateDependencies();
    *   An array of dependencies that will be deleted keyed by dependency type.
    *   Dependency types are, for example, entity, module and theme.
    *
+   * @return bool
+   *   TRUE if the entity has changed, FALSE if not.
+   *
    * @see \Drupal\Core\Config\Entity\ConfigDependencyManager
    * @see \Drupal\Core\Config\ConfigManager::uninstall()
    * @see \Drupal\Core\Entity\EntityDisplayBase::onDependencyRemoval()
diff --git a/core/lib/Drupal/Core/Config/Entity/ThirdPartySettingsTrait.php b/core/lib/Drupal/Core/Config/Entity/ThirdPartySettingsTrait.php
deleted file mode 100644
index cc12885a3157e88338bd6bc44e345ac55dab31f7..0000000000000000000000000000000000000000
--- a/core/lib/Drupal/Core/Config/Entity/ThirdPartySettingsTrait.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Config\Entity\ThirdPartySettingsTrait.
- */
-
-namespace Drupal\Core\Config\Entity;
-
-/**
- * Provides generic implementation of ThirdPartySettingsInterface.
- *
- * The name of the property used to store third party settings is
- * 'third_party_settings'. You need to provide configuration schema for that
- * setting to ensure it is persisted. See 'third_party_settings' defined on
- * field_config_base and other 'field_config.third_party.*' types.
- *
- * @see \Drupal\Core\Config\Entity\ThirdPartySettingsInterface
- */
-trait ThirdPartySettingsTrait {
-
-  /**
-   * Third party entity settings.
-   *
-   * An array of key/value pairs keyed by provider.
-   *
-   * @var array
-   */
-  protected $third_party_settings = array();
-
-  /**
-   * Sets the value of a third-party setting.
-   *
-   * @param string $module
-   *   The module providing the third-party setting.
-   * @param string $key
-   *   The setting name.
-   * @param mixed $value
-   *   The setting value.
-   *
-   * @return $this
-   */
-  public function setThirdPartySetting($module, $key, $value) {
-    $this->third_party_settings[$module][$key] = $value;
-    return $this;
-  }
-
-  /**
-   * Gets the value of a third-party setting.
-   *
-   * @param string $module
-   *   The module providing the third-party setting.
-   * @param string $key
-   *   The setting name.
-   * @param mixed $default
-   *   The default value
-   *
-   * @return mixed
-   *   The value.
-   */
-  public function getThirdPartySetting($module, $key, $default = NULL) {
-    if (isset($this->third_party_settings[$module][$key])) {
-      return $this->third_party_settings[$module][$key];
-    }
-    else {
-      return $default;
-    }
-  }
-
-  /**
-   * Gets all third-party settings of a given module.
-   *
-   * @param string $module
-   *   The module providing the third-party settings.
-   *
-   * @return array
-   *   An array of key-value pairs.
-   */
-  public function getThirdPartySettings($module) {
-    return isset($this->third_party_settings[$module]) ? $this->third_party_settings[$module] : array();
-  }
-
-  /**
-   * Unsets a third-party setting.
-   *
-   * @param string $module
-   *   The module providing the third-party setting.
-   * @param string $key
-   *   The setting name.
-   *
-   * @return mixed
-   *   The value.
-   */
-  public function unsetThirdPartySetting($module, $key) {
-    unset($this->third_party_settings[$module][$key]);
-    // If the third party is no longer storing any information, completely
-    // remove the array holding the settings for this module.
-    if (empty($this->third_party_settings[$module])) {
-      unset($this->third_party_settings[$module]);
-    }
-    return $this;
-  }
-
-  /**
-   * Gets the list of third parties that store information.
-   *
-   * @return array
-   *   The list of third parties.
-   */
-  public function getThirdPartyProviders() {
-    return array_keys($this->third_party_settings);
-  }
-
-}
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index 22f43c1db87351a2dab3382bd8ace6d8ad583b5d..2a9dd9d63c1c440854f108a0f8a7b6a629de9027 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -240,6 +240,8 @@ protected function replaceName($name, $data) {
    * their value or some of these special strings:
    * - '%key', will be replaced by the element's key.
    * - '%parent', to reference the parent element.
+   * - '%type', to reference the schema definition type. Can only be used in
+   *   combination with %parent.
    *
    * There may be nested configuration keys separated by dots or more complex
    * patterns like '%parent.name' which references the 'name' value of the
@@ -249,6 +251,9 @@ protected function replaceName($name, $data) {
    * - 'name.subkey', indicates a nested value of the current element.
    * - '%parent.name', will be replaced by the 'name' value of the parent.
    * - '%parent.%key', will be replaced by the parent element's key.
+   * - '%parent.%type', will be replaced by the schema type of the parent.
+   * - '%parent.%parent.%type', will be replaced by the schema type of the
+   *   parent's parent.
    *
    * @param string $value
    *   Variable value to be replaced.
@@ -273,9 +278,11 @@ protected function replaceVariable($value, $data) {
       else {
         // Get nested value and continue processing.
         if ($name == '%parent') {
+          /** @var \Drupal\Core\Config\Schema\ArrayElement $parent */
           // Switch replacement values with values from the parent.
           $parent = $data['%parent'];
           $data = $parent->getValue();
+          $data['%type'] = $parent->getDataDefinition()->getDataType();
           // The special %parent and %key values now need to point one level up.
           if ($new_parent = $parent->getParent()) {
             $data['%parent'] = $new_parent;
diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
index 05c0144e4e6fd9c4583e965b0f5f9b57f89a0b0b..90d5955807dbf0c2bdd13dd03f02986ae9f545d8 100644
--- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
@@ -8,7 +8,6 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
 use Drupal\field\Entity\FieldConfig;
@@ -20,8 +19,6 @@
  */
 abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDisplayInterface {
 
-  use ThirdPartySettingsTrait;
-
   /**
    * The 'mode' for runtime EntityDisplay objects used to render entities with
    * arbitrary display options rather than a configured view mode or form mode.
@@ -418,7 +415,7 @@ private function fieldHasDisplayOptions(FieldDefinitionInterface $definition) {
    * {@inheritdoc}
    */
   public function onDependencyRemoval(array $dependencies) {
-    $changed = FALSE;
+    $changed = parent::onDependencyRemoval($dependencies);
     foreach ($dependencies['config'] as $entity) {
       if ($entity instanceof FieldConfigInterface) {
         // Remove components for fields that are being deleted.
@@ -437,9 +434,7 @@ public function onDependencyRemoval(array $dependencies) {
         }
       }
     }
-    if ($changed) {
-      $this->save();
-    }
+    return $changed;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php
index af1c3999fbeb0e634d5ad272e929ef4b16fccdbb..7388b4b27ca20acb6e87dba3e565b92162e61ce1 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigBase.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\DependentPluginInterface;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
@@ -20,8 +19,6 @@
  */
 abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigInterface {
 
-  use ThirdPartySettingsTrait;
-
   /**
    * The field ID.
    *
diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php
index a2a3510e771bc391807e6d28ae4312c86598befd..5e5c605f2111c422cacef271f5bfbb587428e682 100644
--- a/core/modules/config/src/Tests/ConfigSchemaTest.php
+++ b/core/modules/config/src/Tests/ConfigSchemaTest.php
@@ -26,7 +26,7 @@ class ConfigSchemaTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'language', 'locale', 'field', 'image', 'config_schema_test');
+  public static $modules = array('system', 'language', 'locale', 'field', 'image', 'config_test', 'config_schema_test');
 
   /**
    * {@inheritdoc}
@@ -172,7 +172,7 @@ function testSchemaMapping() {
     $expected['mapping']['effects']['sequence'][0]['mapping']['uuid']['type'] = 'string';
     $expected['mapping']['third_party_settings']['type'] = 'sequence';
     $expected['mapping']['third_party_settings']['label'] = 'Third party settings';
-    $expected['mapping']['third_party_settings']['sequence'][0]['type'] = 'image_style.third_party.[%key]';
+    $expected['mapping']['third_party_settings']['sequence'][0]['type'] = '[%parent.%parent.%type].third_party.[%key]';
     $expected['type'] = 'image.style.*';
 
     $this->assertEqual($definition, $expected);
@@ -203,6 +203,19 @@ function testSchemaMapping() {
 
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium');
 
+    $test = \Drupal::service('config.typed')->get('config_test.dynamic.third_party')->get('third_party_settings.config_schema_test');
+    $definition = $test->getDataDefinition()->toArray();
+    $expected = array();
+    $expected['type'] = 'config_test.dynamic.*.third_party.config_schema_test';
+    $expected['label'] = 'Mapping';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
+    $expected['mapping'] = [
+      'integer' => ['type' => 'integer'],
+      'string' => ['type' => 'string'],
+    ];
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test');
+
     // More complex, several level deep test.
     $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_one.subsection');
     // This should be the schema of config_schema_test.someschema.somemodule.*.*.
diff --git a/core/modules/config/tests/config_schema_test/config/install/config_test.dynamic.third_party.yml b/core/modules/config/tests/config_schema_test/config/install/config_test.dynamic.third_party.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3db9b1d39b199d32ee0e3428a9980bb0a798560e
--- /dev/null
+++ b/core/modules/config/tests/config_schema_test/config/install/config_test.dynamic.third_party.yml
@@ -0,0 +1,8 @@
+id: third_party
+label: Default
+weight: 0
+protected_property: Default
+third_party_settings:
+  config_schema_test:
+    integer: 1
+    string: 'string'
diff --git a/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml
index 719865a47d248d244388e00a1b9b32ac81084dbb..8c8660c4ee52557a23b2500486e0909bfaa7dbbb 100644
--- a/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml
+++ b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml
@@ -209,3 +209,11 @@ test_with_parents.plugin_types.*:
 
 config_schema_test.hook:
   type: string
+
+config_test.dynamic.*.third_party.config_schema_test:
+  type: mapping
+  mapping:
+    integer:
+      type: integer
+    string:
+      type: string
diff --git a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
index 43575975eec189dfbb6d19287867f67279a70e54..d1c9a576f2bb7acb9fb15c2899249b2884c69854 100644
--- a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
@@ -122,7 +122,7 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
    * {@inheritdoc}
    */
   public function onDependencyRemoval(array $dependencies) {
-    $changed = FALSE;
+    $changed = parent::onDependencyRemoval($dependencies);
     $fix_deps = \Drupal::state()->get('config_test.fix_dependencies', array());
     foreach ($dependencies['config'] as $entity) {
       if (in_array($entity->getConfigDependencyName(), $fix_deps)) {
@@ -133,9 +133,7 @@ public function onDependencyRemoval(array $dependencies) {
         }
       }
     }
-    if ($changed) {
-      $this->save();
-    }
+    return $changed;
   }
 
   /**
diff --git a/core/modules/contact/config/schema/contact.schema.yml b/core/modules/contact/config/schema/contact.schema.yml
index 011ae37016489c8c7154460dd9b7c8215842457b..7ebb6f41a20c8a9ad66873d0a303d4b5010c229f 100644
--- a/core/modules/contact/config/schema/contact.schema.yml
+++ b/core/modules/contact/config/schema/contact.schema.yml
@@ -22,11 +22,6 @@ contact.form.*:
     weight:
       type: integer
       label: 'Weight'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: contact_form.third_party.[%key]
 
 contact.settings:
   type: mapping
diff --git a/core/modules/contact/src/Entity/ContactForm.php b/core/modules/contact/src/Entity/ContactForm.php
index d4be3de6e615445fa9a441d37afe2d61d0433066..c0cf26ad4aa1e4742c47ce9617868914915b0986 100644
--- a/core/modules/contact/src/Entity/ContactForm.php
+++ b/core/modules/contact/src/Entity/ContactForm.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\contact\ContactFormInterface;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 
 /**
  * Defines the contact form entity.
@@ -42,8 +41,6 @@
  */
 class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface {
 
-  use ThirdPartySettingsTrait;
-
   /**
    * The form ID.
    *
diff --git a/core/modules/contact/tests/modules/contact_storage_test/config/schema/contact_storage_test.schema.yml b/core/modules/contact/tests/modules/contact_storage_test/config/schema/contact_storage_test.schema.yml
index e421214f1c61fec98e5e71614a4bcafdc9f50d64..489301e90cf43730314c0d370691400f18780220 100644
--- a/core/modules/contact/tests/modules/contact_storage_test/config/schema/contact_storage_test.schema.yml
+++ b/core/modules/contact/tests/modules/contact_storage_test/config/schema/contact_storage_test.schema.yml
@@ -1,6 +1,6 @@
 # Schema for configuration files of the Contact Storage Test module.
 
-contact_form.third_party.contact_storage_test:
+contact.form.*.third_party.contact_storage_test:
   type: mapping
   label: 'Per-contact form storage settings'
   mapping:
diff --git a/core/modules/content_translation/config/schema/content_translation.schema.yml b/core/modules/content_translation/config/schema/content_translation.schema.yml
index 1e724d8f7a10b5422295e7663f7a330cecae05e4..ddccb5b8ba235326de7fae8e928451b0f8970c7b 100644
--- a/core/modules/content_translation/config/schema/content_translation.schema.yml
+++ b/core/modules/content_translation/config/schema/content_translation.schema.yml
@@ -1,6 +1,6 @@
 # Schema for the Content Translation module.
 
-field_config.third_party.content_translation:
+field.field.*.*.*.third_party.content_translation:
   type: mapping
   label: 'Content translation field settings'
   mapping:
@@ -11,7 +11,7 @@ field_config.third_party.content_translation:
         - type: string
           label: 'Field column for which to synchronize translations'
 
-language.content_settings.third_party.content_translation:
+language.content_settings.*.*.third_party.content_translation:
   type: mapping
   label: 'Content translation content settings'
   mapping:
diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php
index dc4643aaca57edefb868dbb35ce233f7a72764ce..6df0f97a4c6c11e8e9dceecb6fe93747dfa0ad5e 100644
--- a/core/modules/filter/src/Entity/FilterFormat.php
+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -400,7 +400,7 @@ public function removeFilter($instance_id) {
    * {@inheritdoc}
    */
   public function onDependencyRemoval(array $dependencies) {
-    $changed = FALSE;
+    $changed = parent::onDependencyRemoval($dependencies);
     $filters = $this->filters();
     foreach ($filters as $filter) {
       // Remove disabled filters, so that this FilterFormat config entity can
@@ -410,9 +410,7 @@ public function onDependencyRemoval(array $dependencies) {
         $changed = TRUE;
       }
     }
-    if ($changed) {
-      $this->save();
-    }
+    return $changed;
   }
 
   /**
diff --git a/core/modules/image/config/schema/image.schema.yml b/core/modules/image/config/schema/image.schema.yml
index 87f38f69ec8731116cfb0a8455b1f4dfb9fb4950..00268ef6083d583207dd929b3d4d31cc3b4e8a2c 100644
--- a/core/modules/image/config/schema/image.schema.yml
+++ b/core/modules/image/config/schema/image.schema.yml
@@ -22,11 +22,6 @@ image.style.*:
               type: integer
             uuid:
               type: string
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: image_style.third_party.[%key]
 
 image.effect.*:
   type: mapping
diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php
index 4c3775169b6234d3cd6b1b7f4b5d1aa9f615c1e7..a3c7ab534029f2b62934ffce8e1b0ba34c70a27c 100644
--- a/core/modules/image/src/Entity/ImageStyle.php
+++ b/core/modules/image/src/Entity/ImageStyle.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
 use Drupal\Core\Routing\RequestHelper;
@@ -54,8 +53,6 @@
  */
 class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, EntityWithPluginCollectionInterface {
 
-  use ThirdPartySettingsTrait;
-
   /**
    * The name of the image style to use as replacement upon delete.
    *
diff --git a/core/modules/image/tests/modules/image_module_test/config/schema/image_module_test.schema.yml b/core/modules/image/tests/modules/image_module_test/config/schema/image_module_test.schema.yml
index a36719d703156e38257dfe4a89514459cefd7820..b0e8ebf18a6a741ef64906e617e6a1b828bea4f4 100644
--- a/core/modules/image/tests/modules/image_module_test/config/schema/image_module_test.schema.yml
+++ b/core/modules/image/tests/modules/image_module_test/config/schema/image_module_test.schema.yml
@@ -1,4 +1,4 @@
-image_style.third_party.image_module_test:
+image.style.*.third_party.image_module_test:
   type: mapping
   label: 'Schema for image_module_test module additions to image_style entity'
   mapping:
diff --git a/core/modules/language/config/schema/language.schema.yml b/core/modules/language/config/schema/language.schema.yml
index d894eb695ab3de831f26aee6e6b13780b60b97d4..bd03869a2a72d2ec029b213d7b6b051d98ddf984 100644
--- a/core/modules/language/config/schema/language.schema.yml
+++ b/core/modules/language/config/schema/language.schema.yml
@@ -120,11 +120,6 @@ language.content_settings.*.*:
     language_alterable:
       type: boolean
       label: 'Allow to alter the language'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: language.content_settings.third_party.[%key]
 
 condition.plugin.language:
   type: condition.plugin
diff --git a/core/modules/language/src/Entity/ContentLanguageSettings.php b/core/modules/language/src/Entity/ContentLanguageSettings.php
index 607fb4cd580fb60aff027af05358f437b5fc3111..19ca5847779cdada9cb96baff32a193baa292ef4 100644
--- a/core/modules/language/src/Entity/ContentLanguageSettings.php
+++ b/core/modules/language/src/Entity/ContentLanguageSettings.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\language\ContentLanguageSettingsException;
@@ -30,8 +29,6 @@
  */
 class ContentLanguageSettings extends ConfigEntityBase implements ContentLanguageSettingsInterface {
 
-  use ThirdPartySettingsTrait;
-
   /**
    * The id. Combination of $target_entity_type_id.$target_bundle.
    *
diff --git a/core/modules/menu_ui/config/schema/menu_ui.schema.yml b/core/modules/menu_ui/config/schema/menu_ui.schema.yml
index ed1fef8d6072f447187bb8fa329a68f77f3bbd66..ad096f2f2a3a732eb3a8216fbbfa4f645baff115 100644
--- a/core/modules/menu_ui/config/schema/menu_ui.schema.yml
+++ b/core/modules/menu_ui/config/schema/menu_ui.schema.yml
@@ -8,7 +8,7 @@ menu_ui.settings:
       type: boolean
       label: 'Override parent selector'
 
-node_type.third_party.menu_ui:
+node.type.*.third_party.menu_ui:
   type: mapping
   label: 'Per-content type menu settings'
   mapping:
diff --git a/core/modules/node/config/schema/node.schema.yml b/core/modules/node/config/schema/node.schema.yml
index f650794ccdf299d482f1cab7de9cdd49e0f87026..9b8931c738d1c132516331d93ef99708108bcff4 100644
--- a/core/modules/node/config/schema/node.schema.yml
+++ b/core/modules/node/config/schema/node.schema.yml
@@ -33,11 +33,6 @@ node.type.*:
     display_submitted:
       type: boolean
       label: 'Display setting for author and date Submitted by post information'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: node_type.third_party.[%key]
 
 # Plugin \Drupal\node\Plugin\Search\NodeSearch
 search.plugin.node_search:
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 8a08d2670aae6dac1f889856866495689787e902..238ae8f7b0219c742a42adbcc2198e2b09ba5966 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -8,7 +8,6 @@
 namespace Drupal\node\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\node\NodeTypeInterface;
 
@@ -42,7 +41,6 @@
  * )
  */
 class NodeType extends ConfigEntityBundleBase implements NodeTypeInterface {
-  use ThirdPartySettingsTrait;
 
   /**
    * The machine name of this node type.
diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php
index 60d5c33833f2cee224ab8cb0ab15d7905d498da7..01185b57305c6cb7c7d5b57f268a3541bccf8956 100644
--- a/core/modules/node/src/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/src/Tests/NodeTranslationUITest.php
@@ -11,6 +11,7 @@
 use Drupal\content_translation\Tests\ContentTranslationUITest;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Url;
+use Drupal\node\Entity\Node;
 
 /**
  * Tests the Node Translation UI.
@@ -48,6 +49,14 @@ protected function setUp() {
     $this->drupalLogin($this->translator);
   }
 
+  /**
+   * Tests the basic translation UI.
+   */
+  function testTranslationUI() {
+    parent::testTranslationUI();
+    $this->doUninstallTest();
+  }
+
   /**
    * Overrides \Drupal\content_translation\Tests\ContentTranslationUITest::getTranslatorPermission().
    */
@@ -348,4 +357,20 @@ protected function getFormSubmitSuffix(EntityInterface $entity, $langcode) {
     }
     return '';
   }
+
+  /**
+   * Tests uninstalling content_translation.
+   */
+  protected function doUninstallTest() {
+    // Delete all the nodes so there is no data.
+    $nodes = Node::loadMultiple();
+    foreach ($nodes as $node) {
+      $node->delete();
+    }
+    $language_count = count(\Drupal::configFactory()->listAll('language.content_settings.'));
+    \Drupal::service('module_installer')->uninstall(['content_translation']);
+    $this->rebuildContainer();
+    $this->assertEqual($language_count, count(\Drupal::configFactory()->listAll('language.content_settings.')), 'Languages have been fixed rather than deleted during content_translation uninstall.');
+  }
+
 }
diff --git a/core/modules/system/tests/modules/entity_test/config/schema/entity_test.schema.yml b/core/modules/system/tests/modules/entity_test/config/schema/entity_test.schema.yml
index 5a3ad024e9a1c42339e5099cbb9015745709712e..d671bc40141bf29e72660616edbc13aec9848e0d 100644
--- a/core/modules/system/tests/modules/entity_test/config/schema/entity_test.schema.yml
+++ b/core/modules/system/tests/modules/entity_test/config/schema/entity_test.schema.yml
@@ -1,4 +1,4 @@
-entity_view_display.third_party.entity_test:
+core.entity_view_display.*.*.*.third_party.entity_test:
   type: mapping
   label: 'Schema for entity_test module additions to entity_view_display entity'
   mapping:
diff --git a/core/modules/taxonomy/config/schema/taxonomy.schema.yml b/core/modules/taxonomy/config/schema/taxonomy.schema.yml
index cf4a3a97a51e5b76dbe9c343806b18b955e0f202..c79fa5fc6b623d8b75015808ebbdae5dc3c1be9a 100644
--- a/core/modules/taxonomy/config/schema/taxonomy.schema.yml
+++ b/core/modules/taxonomy/config/schema/taxonomy.schema.yml
@@ -33,11 +33,6 @@ taxonomy.vocabulary.*:
     weight:
       type: integer
       label: 'Weight'
-    third_party_settings:
-      type: sequence
-      label: 'Third party settings'
-      sequence:
-        - type: taxonomy.vocabulary.third_party.[%key]
 
 field.storage_settings.taxonomy_term_reference:
   type: base_entity_reference_field_settings
diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index 4f21f8a781fda39ba6ca2c768fe69f106ce47b3c..ae7b10f1e5d487339b3d701ee60a771af4228dd3 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -8,7 +8,6 @@
 namespace Drupal\taxonomy\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\taxonomy\VocabularyInterface;
 
@@ -46,7 +45,6 @@
  * )
  */
 class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
-  use ThirdPartySettingsTrait;
 
   /**
    * The taxonomy vocabulary ID.
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_crud/config/schema/taxonomy_crud.schema.yml b/core/modules/taxonomy/tests/modules/taxonomy_crud/config/schema/taxonomy_crud.schema.yml
index fdbed04c90c65ba6c5452c90d09e0baa8a6be57a..fdbffe9d0b7a9c58ace4fb3e0f0592db330fcbb3 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_crud/config/schema/taxonomy_crud.schema.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_crud/config/schema/taxonomy_crud.schema.yml
@@ -1,4 +1,4 @@
-taxonomy.vocabulary.third_party.taxonomy_crud:
+taxonomy.vocabulary.*.third_party.taxonomy_crud:
   type: mapping
   label: 'Schema for taxonomy_crud module additions to vocabulary entity'
   mapping:
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index 7af62e5db273d354e9e9f176872deaa61a3b5d11..9456d33c81c56d7f5096b15379b808b45e83268a 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -291,14 +291,20 @@ public function providerCalculateDependenciesWithPluginCollections() {
 
   /**
    * @covers ::calculateDependencies
+   * @covers ::onDependencyRemoval
    */
   public function testCalculateDependenciesWithThirdPartySettings() {
-    $this->entity = $this->getMockForAbstractClass('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithThirdPartySettings', array(array(), $this->entityTypeId));
+    $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array(array(), $this->entityTypeId));
     $this->entity->setThirdPartySetting('test_provider', 'test', 'test');
     $this->entity->setThirdPartySetting('test_provider2', 'test', 'test');
     $this->entity->setThirdPartySetting($this->provider, 'test', 'test');
 
     $this->assertEquals(array('test_provider', 'test_provider2'), $this->entity->calculateDependencies()['module']);
+    $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider2']]);
+    $this->assertTrue($changed, 'Calling onDependencyRemoval with an existing third party dependency provider returns TRUE.');
+    $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider3']]);
+    $this->assertFalse($changed, 'Calling onDependencyRemoval with a non-existing third party dependency provider returns FALSE.');
+    $this->assertEquals(array('test_provider'), $this->entity->calculateDependencies()['module']);
   }
 
   /**
@@ -467,4 +473,38 @@ public function testToArrayFallback() {
     $this->entity->toArray();
   }
 
+  /**
+   * @covers ::getThirdPartySetting
+   * @covers ::setThirdPartySetting
+   * @covers ::getThirdPartySettings
+   * @covers ::unsetThirdPartySetting
+   * @covers ::getThirdPartyProviders
+   */
+  public function testThirdPartySettings() {
+    $key = 'test';
+    $third_party = 'test_provider';
+    $value = $this->getRandomGenerator()->string();
+
+    // Test getThirdPartySetting() with no settings.
+    $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $value));
+    $this->assertNull($this->entity->getThirdPartySetting($third_party, $key));
+
+    // Test setThirdPartySetting().
+    $this->entity->setThirdPartySetting($third_party, $key, $value);
+    $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key));
+    $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $this->randomGenerator->string()));
+
+    // Test getThirdPartySettings().
+    $this->entity->setThirdPartySetting($third_party, 'test2', 'value2');
+    $this->assertEquals(array($key => $value, 'test2' => 'value2'), $this->entity->getThirdPartySettings($third_party));
+
+    // Test getThirdPartyProviders().
+    $this->entity->setThirdPartySetting('test_provider2', $key, $value);
+    $this->assertEquals(array($third_party, 'test_provider2'), $this->entity->getThirdPartyProviders());
+
+    // Test unsetThirdPartyProviders().
+    $this->entity->unsetThirdPartySetting('test_provider2', $key);
+    $this->assertEquals(array($third_party), $this->entity->getThirdPartyProviders());
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/Fixtures/ConfigEntityBaseWithThirdPartySettings.php b/core/tests/Drupal/Tests/Core/Config/Entity/Fixtures/ConfigEntityBaseWithThirdPartySettings.php
deleted file mode 100644
index 6834e63bba384161788c0e6f57c1f1576b4c4ffa..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Core/Config/Entity/Fixtures/ConfigEntityBaseWithThirdPartySettings.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithThirdPartySettings.
- */
-
-namespace Drupal\Tests\Core\Config\Entity\Fixtures;
-
-use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Config\Entity\ThirdPartySettingsInterface;
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
-
-/**
- * Enables testing of dependency calculation.
- *
- * @see \Drupal\Tests\Core\Config\Entity\ConfigEntityBaseUnitTest::testCalculateDependenciesWithThirdPartySettings()
- * @see \Drupal\Core\Config\Entity\ConfigEntityBase::calculateDependencies()
- */
-abstract class ConfigEntityBaseWithThirdPartySettings extends ConfigEntityBase implements ThirdPartySettingsInterface {
-  use ThirdPartySettingsTrait;
-
-}
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ThirdPartySettingsTraitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ThirdPartySettingsTraitTest.php
deleted file mode 100644
index bcbe12bf2b3e9bc4fc93fd17cab99be4bb22c04d..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ThirdPartySettingsTraitTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Tests\Core\Config\Entity\ThirdPartySettingsTraitTest.
- */
-
-namespace Drupal\Tests\Core\Config\Entity;
-
-use Drupal\Core\Config\Entity\ThirdPartySettingsTrait;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\Core\Config\Entity\ThirdPartySettingsTrait
- * @group Config
- */
-class ThirdPartySettingsTraitTest extends UnitTestCase {
-
-  /**
-   * @covers ::getThirdPartySetting
-   * @covers ::setThirdPartySetting
-   * @covers ::getThirdPartySettings
-   * @covers ::unsetThirdPartySetting
-   * @covers ::getThirdPartyProviders
-   */
-  public function testThirdPartySettings() {
-    $key = 'test';
-    $third_party = 'test_provider';
-    $value = $this->getRandomGenerator()->string();
-
-    $trait_object = new TestThirdPartySettingsTrait();
-
-    // Test getThirdPartySetting() with no settings.
-    $this->assertEquals($value, $trait_object->getThirdPartySetting($third_party, $key, $value));
-    $this->assertNull($trait_object->getThirdPartySetting($third_party, $key));
-
-    // Test setThirdPartySetting().
-    $trait_object->setThirdPartySetting($third_party, $key, $value);
-    $this->assertEquals($value, $trait_object->getThirdPartySetting($third_party, $key));
-    $this->assertEquals($value, $trait_object->getThirdPartySetting($third_party, $key, $this->randomGenerator->string()));
-
-    // Test getThirdPartySettings().
-    $trait_object->setThirdPartySetting($third_party, 'test2', 'value2');
-    $this->assertEquals(array($key => $value, 'test2' => 'value2'), $trait_object->getThirdPartySettings($third_party));
-
-    // Test getThirdPartyProviders().
-    $trait_object->setThirdPartySetting('test_provider2', $key, $value);
-    $this->assertEquals(array($third_party, 'test_provider2'), $trait_object->getThirdPartyProviders());
-
-    // Test unsetThirdPartyProviders().
-    $trait_object->unsetThirdPartySetting('test_provider2', $key);
-    $this->assertEquals(array($third_party), $trait_object->getThirdPartyProviders());
-  }
-}
-
-class TestThirdPartySettingsTrait {
-
-  use ThirdPartySettingsTrait;
-
-}