diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
index cb8b4cba691edd010a7b9fe265e96199ce001f4b..3ad3acfe54253068ee50f1fcadeef96350ae6702 100644
--- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
@@ -83,20 +83,6 @@ class FieldableDatabaseStorageController extends FieldableEntityStorageControlle
    */
   protected $fieldInfo;
 
-  /**
-   * The entity bundle key.
-   *
-   * @var string|bool
-   */
-  protected $bundleKey = FALSE;
-
-  /**
-   * Name of the entity class.
-   *
-   * @var string
-   */
-  protected $entityClass;
-
   /**
    * {@inheritdoc}
    */
@@ -123,8 +109,6 @@ public function __construct(EntityTypeInterface $entity_info, Connection $databa
 
     $this->database = $database;
     $this->fieldInfo = $field_info;
-    $this->bundleKey = $this->entityInfo->getKey('bundle');
-    $this->entityClass = $this->entityInfo->getClass();
 
     // Check if the entity type supports IDs.
     if ($this->entityInfo->hasKey('id')) {
@@ -151,46 +135,6 @@ public function __construct(EntityTypeInterface $entity_info, Connection $databa
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function create(array $values) {
-    $entity_class = $this->entityClass;
-    $entity_class::preCreate($this, $values);
-
-    // We have to determine the bundle first.
-    $bundle = FALSE;
-    if ($this->bundleKey) {
-      if (!isset($values[$this->bundleKey])) {
-        throw new EntityStorageException(format_string('Missing bundle for entity type @type', array('@type' => $this->entityType)));
-      }
-      $bundle = $values[$this->bundleKey];
-    }
-    $entity = new $entity_class(array(), $this->entityType, $bundle);
-
-    foreach ($entity as $name => $field) {
-      if (isset($values[$name])) {
-        $entity->$name = $values[$name];
-      }
-      elseif (!array_key_exists($name, $values)) {
-        $entity->get($name)->applyDefaultValue();
-      }
-      unset($values[$name]);
-    }
-
-    // Set any passed values for non-defined fields also.
-    foreach ($values as $name => $value) {
-      $entity->$name = $value;
-    }
-    $entity->postCreate($this);
-
-    // Modules might need to add or change the data initially held by the new
-    // entity object, for instance to fill-in default values.
-    $this->invokeHook('create', $entity);
-
-    return $entity;
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -1243,6 +1187,50 @@ public static function _fieldSqlSchema(FieldInterface $field, array $schema = NU
       $description_revision = "Revision archive storage for {$field->entity_type} field {$field->getName()}.";
     }
 
+    $entity_type = $field->entity_type;
+    $entity_manager = \Drupal::entityManager();
+    $info = $entity_manager->getDefinition($entity_type);
+    $definitions = $entity_manager->getFieldDefinitions($entity_type);
+
+    // Define the entity ID schema based on the field definitions.
+    $id_definition = $definitions[$info->getKey('id')];
+    if ($id_definition->getType() == 'integer') {
+      $id_schema = array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The entity id this data is attached to',
+      );
+    }
+    else {
+      $id_schema = array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'description' => 'The entity id this data is attached to',
+      );
+    }
+
+    // Define the revision ID schema, default to integer if there is no revision
+    // ID.
+    $revision_id_definition = $info->hasKey('revision_id') ? $definitions[$info->getKey('revision_id')] : NULL;
+    if (!$revision_id_definition || $revision_id_definition->getType() == 'integer') {
+      $revision_id_schema = array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+        'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
+      );
+    }
+    else {
+      $revision_id_schema = array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => FALSE,
+        'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
+      );
+    }
+
     $current = array(
       'description' => $description_current,
       'fields' => array(
@@ -1260,18 +1248,8 @@ public static function _fieldSqlSchema(FieldInterface $field, array $schema = NU
           'default' => 0,
           'description' => 'A boolean indicating whether this data item has been deleted'
         ),
-        'entity_id' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'description' => 'The entity id this data is attached to',
-        ),
-        'revision_id' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => FALSE,
-          'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
-        ),
+        'entity_id' => $id_schema,
+        'revision_id' => $revision_id_schema,
         'langcode' => array(
           'type' => 'varchar',
           'length' => 32,
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
index 9aa3a63986dd1089980a3fbb5f2e8e4fab953185..02755974d55124c64f9e4e60f53f86cde5e7daf8 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
@@ -7,14 +7,91 @@
 
 namespace Drupal\Core\Entity;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Field\PrepareCacheInterface;
 use Drupal\field\FieldInterface;
 use Drupal\field\FieldInstanceInterface;
 use Drupal\Core\Field\ConfigFieldItemListInterface;
-use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 abstract class FieldableEntityStorageControllerBase extends EntityStorageControllerBase implements FieldableEntityStorageControllerInterface {
 
+  /**
+   * The entity bundle key.
+   *
+   * @var string|bool
+   */
+  protected $bundleKey = FALSE;
+
+  /**
+   * Name of the entity class.
+   *
+   * @var string
+   */
+  protected $entityClass;
+
+  /**
+   * Constructs a FieldableEntityStorageControllerBase object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_info
+   *   The entity info for the entity type.
+   */
+  public function __construct(EntityTypeInterface $entity_info) {
+    parent::__construct($entity_info);
+
+    $this->bundleKey = $this->entityInfo->getKey('bundle');
+    $this->entityClass = $this->entityInfo->getClass();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_info) {
+    return new static(
+      $entity_info
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function create(array $values) {
+    $entity_class = $this->entityInfo->getClass();
+    $entity_class::preCreate($this, $values);
+
+    // We have to determine the bundle first.
+    $bundle = FALSE;
+    if ($this->bundleKey) {
+      if (!isset($values[$this->bundleKey])) {
+        throw new EntityStorageException(String::format('Missing bundle for entity type @type', array('@type' => $this->entityType)));
+      }
+      $bundle = $values[$this->bundleKey];
+    }
+    $entity = new $entity_class(array(), $this->entityType, $bundle);
+
+    foreach ($entity as $name => $field) {
+      if (isset($values[$name])) {
+        $entity->$name = $values[$name];
+      }
+      elseif (!array_key_exists($name, $values)) {
+        $entity->get($name)->applyDefaultValue();
+      }
+      unset($values[$name]);
+    }
+
+    // Set any passed values for non-defined fields also.
+    foreach ($values as $name => $value) {
+      $entity->$name = $value;
+    }
+    $entity->postCreate($this);
+
+    // Modules might need to add or change the data initially held by the new
+    // entity object, for instance to fill-in default values.
+    $this->invokeHook('create', $entity);
+
+    return $entity;
+  }
+
   /**
    * Loads values of configurable fields for a group of entities.
    *
diff --git a/core/lib/Drupal/Core/Entity/FieldableNullStorageController.php b/core/lib/Drupal/Core/Entity/FieldableNullStorageController.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f0288473332e9aab9d0e9f49db8ed9b035ca91a
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/FieldableNullStorageController.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\FieldableNullStorageController.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Entity\Query\QueryException;
+use Drupal\field\FieldInstanceInterface;
+
+/**
+ * Defines a null entity controller class.
+ *
+ * Used for content entity types that have no storage.
+ */
+class FieldableNullStorageController extends FieldableEntityStorageControllerBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadMultiple(array $ids = NULL) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function load($id) {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadRevision($revision_id) {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteRevision($revision_id) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadByProperties(array $values = array()) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete(array $entities) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(EntityInterface $entity) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQueryServiceName() {
+    throw new QueryException('Null implementation can not be queried.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doLoadFieldItems($entities, $age) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doSaveFieldItems(EntityInterface $entity, $update) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doDeleteFieldItems(EntityInterface $entity) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doDeleteFieldItemsRevision(EntityInterface $entity) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function readFieldItemsToPurge(EntityInterface $entity, FieldInstanceInterface $instance) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function purgeFieldItems(EntityInterface $entity, FieldInstanceInterface $instance) {
+  }
+
+}
diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
index f12bbf4628ca731ab182d8e05a5507e2859755a0..b8a1523c12df3dc9f7b4032311e0e9d934db4e25 100644
--- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php
+++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
@@ -18,7 +18,7 @@
  *   id = "contact_message",
  *   label = @Translation("Contact message"),
  *   controllers = {
- *     "storage" = "Drupal\Core\Entity\FieldableDatabaseStorageController",
+ *     "storage" = "Drupal\Core\Entity\FieldableNullStorageController",
  *     "view_builder" = "Drupal\contact\MessageViewBuilder",
  *     "form" = {
  *       "default" = "Drupal\contact\MessageFormController"
diff --git a/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php b/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..81dd807dbba691fe09a83f347e66f5c905b5f50b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Entity/FieldableDatabaseStorageControllerTest.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Entity\FieldableDatabaseStorageControllerTest.
+ */
+
+namespace Drupal\Tests\Core\Entity;
+
+use Drupal\Core\Entity\EntityType;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
+use Drupal\Core\Field\FieldDefinition;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * Tests the fieldable database storage controller.
+ *
+ * @see \Drupal\Core\Entity\FieldableDatabaseStorageController
+ *
+ * @group Drupal
+ * @group Entity
+ */
+class FieldableDatabaseStorageControllerTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Fieldable database storage controller',
+      'description' => 'Tests the fieldable database storage enhancer for entities.',
+      'group' => 'Entity'
+    );
+  }
+
+  /**
+   * Tests field SQL schema generation for an entity with a string identifier.
+   *
+   * @see \Drupal\Core\Entity\Controller\FieldableDatabaseStorageController::_fieldSqlSchema()
+   */
+  public function testFieldSqlSchemaForEntityWithStringIdentifier() {
+
+    // Mock the entity manager to return the minimal entity and field
+    // definitions for the test_entity entity.
+    $definition = new EntityType(array(
+      'entity_keys' => array(
+        'id' => 'id',
+        'revision_id' => 'revision_id',
+      ),
+    ));
+    $fields['id'] = FieldDefinition::create('string')
+      ->setName('id');
+    $fields['revision_id'] = FieldDefinition::create('string')
+      ->setName('revision_id');
+
+    $entity_manager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
+    $entity_manager->expects($this->any())
+      ->method('getDefinition')
+      ->with('test_entity')
+      ->will($this->returnValue($definition));
+
+    $entity_manager->expects($this->any())
+      ->method('getFieldDefinitions')
+      ->with('test_entity')
+      ->will($this->returnValue($fields));
+
+    $container = new ContainerBuilder();
+    $container->set('entity.manager', $entity_manager);
+    \Drupal::setContainer($container);
+
+    // Define a field definition for a test_field field.
+    $field = $this->getMock('\Drupal\field\FieldInterface');
+    $field->deleted = FALSE;
+    $field->entity_type = 'test_entity';
+    $field->name = 'test_field';
+
+    $field->expects($this->any())
+      ->method('getName')
+      ->will($this->returnValue('test'));
+
+    $field_schema = array(
+      'columns' => array(
+        'value' => array(
+          'type' => 'varchar',
+          'length' => 10,
+          'not null' => FALSE,
+        ),
+      ),
+      'indexes' => array(),
+      'foreign keys' => array(),
+    );
+    $field->expects($this->any())
+      ->method('getSchema')
+      ->will($this->returnValue($field_schema));
+
+    $schema = FieldableDatabaseStorageController::_fieldSqlSchema($field);
+
+    // Make sure that the entity_id schema field if of type varchar.
+    $this->assertEquals($schema['test_entity__test_field']['fields']['entity_id']['type'], 'varchar');
+    $this->assertEquals($schema['test_entity__test_field']['fields']['revision_id']['type'], 'varchar');
+  }
+
+}