diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index b943d17..f5197f9 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -249,14 +249,17 @@ public function toArray() {
       throw new SchemaIncompleteException(String::format('Incomplete or missing schema for @config_name', array('@config_name' => $config_name)));
     }
     $id_key = $this->getEntityType()->getKey('id');
+    $config_mapping = $this->getEntityType()->getConfigMapping();
     foreach (array_keys($definition['mapping']) as $name) {
+      // Check for a config mapping, otherwise use the default name.
+      $property_name = isset($config_mapping[$name]) ? $config_mapping[$name] : $name;
       // Special handling for IDs so that computed compound IDs work.
       // @see \Drupal\Core\Entity\EntityDisplayBase::id()
-      if ($name == $id_key) {
+      if ($property_name == $id_key) {
         $properties[$name] = $this->id();
       }
       else {
-        $properties[$name] = $this->get($name);
+        $properties[$name] = $this->get($property_name);
       }
     }
     return $properties;
@@ -274,6 +277,21 @@ protected function getTypedConfig() {
   /**
    * {@inheritdoc}
    */
+  public static function preCreate(EntityStorageInterface $storage, array &$values) {
+    // If needed, map the config keys to entity properties.
+    $config_mapping = $storage->getEntityType()->getConfigMapping();
+    foreach ($values as $key => $value) {
+      if (isset($config_mapping[$key])) {
+        $new_key = $config_mapping[$key];
+        $values[$new_key] = $value;
+        unset($values[$key]);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityForm.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityForm.php
new file mode 100644
index 0000000..7a78f07
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityForm.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\Entity\ConfigEntityForm.
+ */
+
+namespace Drupal\Core\Config\Entity;
+
+use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Entity form variant for config entity types.
+ *
+ * @see \Drupal\Core\Config\Entity\ConfigEntityBase
+ */
+class ConfigEntityForm extends EntityForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
+    $values = $form_state->getValues();
+
+    if ($this->entity instanceof EntityWithPluginCollectionInterface) {
+      // Do not manually update values represented by plugin collections.
+      $values = array_diff_key($values, $this->entity->getPluginCollections());
+    }
+
+    $config_mapping = $this->entity->getEntityType()->getConfigMapping();
+    foreach ($values as $key => $value) {
+      // If needed, map the config keys to entity properties.
+      $property_name = isset($config_mapping[$key]) ? $config_mapping[$key] : $key;
+      $entity->set($property_name, $value);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
index 23b0f4a..845e3ee 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
@@ -56,6 +56,13 @@ class ConfigEntityType extends EntityType {
   protected $config_prefix;
 
   /**
+   * Returns the array mapping config keys to entity properties.
+   *
+   * @var array
+   */
+  protected $config_mapping = [];
+
+  /**
    * {@inheritdoc}
    */
   protected $static_cache = FALSE;
@@ -107,6 +114,13 @@ public function getConfigPrefix() {
   /**
    * {@inheritdoc}
    */
+  public function getConfigMapping() {
+    return $this->config_mapping;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getBaseTable() {
     return FALSE;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index a0b18fa..f8fb0df 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -299,19 +299,7 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
    *   The current state of the form.
    */
   protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
-    $values = $form_state->getValues();
-
-    if ($this->entity instanceof EntityWithPluginCollectionInterface) {
-      // Do not manually update values represented by plugin collections.
-      $values = array_diff_key($values, $this->entity->getPluginCollections());
-    }
-
-    // @todo: This relies on a method that only exists for config and content
-    //   entities, in a different way. Consider moving this logic to a config
-    //   entity specific implementation.
-    foreach ($values as $key => $value) {
-      $entity->set($key, $value);
-    }
+    // Overriden by ConfigEntityForm and ContentEntityForm with specific logic.
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php
index b23cd9d..a26ffc4 100644
--- a/core/lib/Drupal/Core/Entity/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -630,6 +630,13 @@ public function getConfigPrefix() {
   /**
    * {@inheritdoc}
    */
+  public function getConfigMapping() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getRevisionDataTable() {
     return $this->revision_data_table;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
index 49302d3..fc100c7 100644
--- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
@@ -588,6 +588,16 @@ public function isRevisionable();
   public function getConfigPrefix();
 
   /**
+   * Returns the config mapping used by the configuration entity type.
+   *
+   * @todo Used for configuration entities only.
+   *
+   * @return array
+   *   An array mapping each config key to its entity property.
+   */
+  public function getConfigMapping();
+
+  /**
    * Returns the name of the entity's revision data table.
    *
    * @todo Used by SqlContentEntityStorage only.
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 8a08d26..fa1e18f 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -29,6 +29,11 @@
  *   },
  *   admin_permission = "administer content types",
  *   config_prefix = "type",
+ *   config_mapping = {
+ *     "new_revision" = "newRevision",
+ *     "preview_mode" = "previewMode",
+ *     "display_submitted" = "displaySubmitted",
+ *   },
  *   bundle_of = "node",
  *   entity_keys = {
  *     "id" = "type",
@@ -81,21 +86,21 @@ class NodeType extends ConfigEntityBundleBase implements NodeTypeInterface {
    *
    * @var bool
    */
-  protected $new_revision = FALSE;
+  protected $newRevision = FALSE;
 
   /**
    * The preview mode.
    *
    * @var int
    */
-  protected $preview_mode = DRUPAL_OPTIONAL;
+  protected $previewMode = DRUPAL_OPTIONAL;
 
   /**
    * Display setting for author and date Submitted by post information.
    *
    * @var bool
    */
-  protected $display_submitted = TRUE;
+  protected $displaySubmitted = TRUE;
 
   /**
    * {@inheritdoc}
@@ -116,42 +121,42 @@ public function isLocked() {
    * {@inheritdoc}
    */
   public function isNewRevision() {
-    return $this->new_revision;
+    return $this->newRevision;
   }
 
   /**
    * {@inheritdoc}
    */
   public function setNewRevision($new_revision) {
-    $this->new_revision = $new_revision;
+    $this->newRevision = $new_revision;
   }
 
   /**
    * {@inheritdoc}
    */
   public function displaySubmitted() {
-    return $this->display_submitted;
+    return $this->displaySubmitted;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setDisplaySubmitted($display_submtited) {
-    $this->display_submitted = $display_submtited;
+  public function setDisplaySubmitted($display_submitted) {
+    $this->displaySubmitted = $display_submitted;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getPreviewMode() {
-    return $this->preview_mode;
+    return $this->previewMode;
   }
 
   /**
    * {@inheritdoc}
    */
   public function setPreviewMode($preview_mode) {
-    $this->preview_mode = $preview_mode;
+    $this->previewMode = $preview_mode;
   }
 
   /**
diff --git a/core/modules/node/src/NodeTypeForm.php b/core/modules/node/src/NodeTypeForm.php
index 2292cf0..c7847a6 100644
--- a/core/modules/node/src/NodeTypeForm.php
+++ b/core/modules/node/src/NodeTypeForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Config\Entity\ConfigEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityTypeInterface;
@@ -19,7 +19,7 @@
 /**
  * Form controller for node type forms.
  */
-class NodeTypeForm extends EntityForm {
+class NodeTypeForm extends ConfigEntityForm {
 
   /**
    * The entity manager.
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index 7af62e5..d5d03d8 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -7,9 +7,7 @@
 
 namespace Drupal\Tests\Core\Config\Entity;
 
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Component\Plugin\PluginBase;
 use Drupal\Core\Language\Language;
 use Drupal\Tests\Core\Plugin\Fixtures\TestConfigurablePlugin;
 use Drupal\Tests\UnitTestCase;
@@ -95,11 +93,6 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
    */
   protected function setUp() {
     $this->id = $this->randomMachineName();
-    $values = array(
-      'id' => $this->id,
-      'langcode' => 'en',
-      'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
-    );
     $this->entityTypeId = $this->randomMachineName();
     $this->provider = $this->randomMachineName();
     $this->entityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface');
@@ -136,7 +129,24 @@ protected function setUp() {
     $container->set('config.typed', $this->typedConfigManager);
     \Drupal::setContainer($container);
 
-    $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId));
+    $this->entity = $this->setUpEntity();
+  }
+
+  /**
+   * Sets up an entity object for testing.
+   *
+   * @param array $values
+   *   An array of values to pass to the entity constructor.
+   *
+   * @return \Drupal\Core\Config\Entity\ConfigEntityBase|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected function setUpEntity(array $values = []) {
+    $values += array(
+      'id' => $this->id,
+      'langcode' => 'en',
+      'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
+    );
+    return $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', array($values, $this->entityTypeId));
   }
 
   /**
@@ -467,4 +477,33 @@ public function testToArrayFallback() {
     $this->entity->toArray();
   }
 
+  /**
+   * @covers ::preCreate
+   * @covers ::toArray
+   */
+  public function testToArrayConfigMapping() {
+    $this->typedConfigManager->expects($this->once())
+      ->method('getDefinition')
+      ->will($this->returnValue(['mapping' => ['id' => '', 'dependencies' => '', 'foo_bar' => '']]));
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getConfigMapping')
+      ->willReturn(['foo_bar' => 'fooBar']);
+    $storage = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
+    $storage->expects($this->any())
+      ->method('getEntityType')
+      ->will($this->returnValue($this->entityType));
+
+    // Confirm that preCreate() maps the values as expected.
+    $values = ['foo_bar' => 5];
+    $entity_class = get_class($this->entity);
+    $entity_class::preCreate($storage, $values);
+    $this->assertEquals(['fooBar' => 5], $values);
+
+    // Confirm that toArray() maps the properties back to config keys.
+    $this->entity = $this->setUpEntity($values);
+    $properties = $this->entity->toArray(true);
+    $this->assertInternalType('array', $properties);
+    $this->assertEquals(['id' => $this->entity->id(), 'dependencies' => [], 'foo_bar' => 5], $properties);
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityFormTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityFormTest.php
new file mode 100644
index 0000000..43a5773
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityFormTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Config\Entity\ConfigEntityFormTest.
+ */
+
+namespace Drupal\Tests\Core\Config\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityForm;
+use Drupal\Core\Form\FormState;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityForm
+ * @group Config
+ */
+class ConfigEntityFormTest extends UnitTestCase {
+
+  /**
+   * The config entity form.
+   *
+   * @var \Drupal\Core\Config\Entity\ConfigEntityForm
+   */
+  protected $entityForm;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->entityForm = new ConfigEntityForm();
+  }
+
+  /**
+   * @covers ::copyFormValuesToEntity
+   */
+  public function testCopyFormValuesToEntity() {
+    $entity_id = 'test_config_entity_id';
+    $values = ['id' => $entity_id];
+    $entity_type = $this->getMockBuilder('\Drupal\Core\Config\Entity\ConfigEntityType')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity_type->expects($this->atLeastOnce())
+      ->method('getConfigMapping')
+      ->willReturn(['regular_key' => 'regularKey']);
+    $entity = $this->getMockBuilder('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections')
+      ->setConstructorArgs([$values, 'test_config_entity'])
+      ->setMethods(['getEntityType', 'getPluginCollections'])
+      ->getMock();
+    $entity->expects($this->atLeastOnce())
+      ->method('getEntityType')
+      ->willReturn($entity_type);
+    $entity->expects($this->atLeastOnce())
+      ->method('getPluginCollections')
+      ->willReturn(['key_controlled_by_plugin_collection' => NULL]);
+    $this->entityForm->setEntity($entity);
+
+    $form_state = (new FormState())->setValues([
+      'regular_key' => 'foo',
+      'key_controlled_by_plugin_collection' => 'bar',
+    ]);
+    $result = $this->entityForm->buildEntity([], $form_state);
+
+    $this->assertSame($entity_id, $result->id());
+    // The regular key should have a value, but the one controlled by a plugin
+    // collection should not have been set.
+    $this->assertSame('foo', $result->get('regularKey'));
+    $this->assertNull($result->get('key_controlled_by_plugin_collection'));
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php
index ea39a9d..adfc714 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityFormTest.php
@@ -8,7 +8,6 @@
 namespace Drupal\Tests\Core\Entity;
 
 use Drupal\Core\Entity\EntityForm;
-use Drupal\Core\Form\FormState;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -95,32 +94,4 @@ public function providerTestFormIds() {
     );
   }
 
-  /**
-   * @covers ::copyFormValuesToEntity
-   */
-  public function testCopyFormValuesToEntity() {
-    $entity_id = 'test_config_entity_id';
-    $values = ['id' => $entity_id];
-    $entity = $this->getMockBuilder('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections')
-      ->setConstructorArgs([$values, 'test_config_entity'])
-      ->setMethods(['getPluginCollections'])
-      ->getMock();
-    $entity->expects($this->atLeastOnce())
-      ->method('getPluginCollections')
-      ->willReturn(['key_controlled_by_plugin_collection' => NULL]);
-    $this->entityForm->setEntity($entity);
-
-    $form_state = (new FormState())->setValues([
-      'regular_key' => 'foo',
-      'key_controlled_by_plugin_collection' => 'bar',
-    ]);
-    $result = $this->entityForm->buildEntity([], $form_state);
-
-    $this->assertSame($entity_id, $result->id());
-    // The regular key should have a value, but the one controlled by a plugin
-    // collection should not have been set.
-    $this->assertSame('foo', $result->get('regular_key'));
-    $this->assertNull($result->get('key_controlled_by_plugin_collection'));
-  }
-
 }
