diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
index 3ecce46..e184e9f 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
@@ -56,6 +56,18 @@ public function getTargetDefinition() {
   }
 
   /**
+   * Checks whether the target entity has not been saved yet.
+   *
+   * @return bool
+   *   TRUE if the entity is new, FALSE otherwise.
+   */
+  public function isTargetNew() {
+    // We assume that if the target entity is not set we cannot have a new
+    // entity.
+    return !isset($this->id) && isset($this->target) && $this->target->getValue()->isNew();
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getTarget() {
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index d3087b7..83b3f49 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -1023,6 +1023,7 @@ protected function processIdentifierSchema(&$schema, $key) {
     if ($schema['fields'][$key]['type'] == 'int') {
       $schema['fields'][$key]['type'] = 'serial';
     }
+    $schema['fields'][$key]['not null'] = TRUE;
     unset($schema['fields'][$key]['default']);
   }
 
@@ -1390,27 +1391,37 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
 
     $field_name = $storage_definition->getName();
     $field_description = $storage_definition->getDescription();
+    $base_table = $this->storage->getBaseTable();
+
+    // A shared table contains rows for entities where the field is empty
+    // (since other fields stored in the same table might not be empty), thus
+    // the only columns that can be 'not null' are those for required
+    // properties of required fields. However, even those would break in the
+    // case where a new field is added to a table that contains existing rows.
+    // For now, we only hardcode 'not null' to a couple "entity keys", in order
+    // to keep their indexes optimized.
+    // @todo Revisit once we have support for 'initial' in
+    //   https://www.drupal.org/node/2346019.
+    $not_null_keys = $this->entityType->getKeys() + array('langcode' => 'langcode');
+    // Label fields are not necessarily required.
+    unset($not_null_keys['label']);
+    // Because entity ID and revision ID are both serial fields in the base and
+    // revision table respectively, the revision ID is not known yet, when
+    // inserting data into the base table. Instead the revision ID in the base
+    // table is updated after the data has been inserted into the revision
+    // table. For this reason the revision ID field cannot be marked as NOT
+    // NULL.
+    if ($table_name == $base_table) {
+      unset($not_null_keys['revision']);
+    }
 
     foreach ($column_mapping as $field_column_name => $schema_field_name) {
       $column_schema = $field_schema['columns'][$field_column_name];
 
       $schema['fields'][$schema_field_name] = $column_schema;
       $schema['fields'][$schema_field_name]['description'] = $field_description;
-      // Only entity keys are required.
-      $keys = $this->entityType->getKeys() + array('langcode' => 'langcode');
-      // The label is an entity key, but label fields are not necessarily
-      // required.
-      // Because entity ID and revision ID are both serial fields in the base
-      // and revision table respectively, the revision ID is not known yet, when
-      // inserting data into the base table. Instead the revision ID in the base
-      // table is updated after the data has been inserted into the revision
-      // table. For this reason the revision ID field cannot be marked as NOT
-      // NULL.
-      unset($keys['label'], $keys['revision']);
-      // Key fields may not be NULL.
-      if (in_array($field_name, $keys)) {
-        $schema['fields'][$schema_field_name]['not null'] = TRUE;
-      }
+
+      $schema['fields'][$schema_field_name]['not null'] = in_array($field_name, $not_null_keys);
     }
 
     if (!empty($field_schema['indexes'])) {
@@ -1600,6 +1611,7 @@ protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $stor
 
     // Check that the schema does not include forbidden column names.
     $schema = $storage_definition->getSchema();
+    $properties = $storage_definition->getPropertyDefinitions();
     $table_mapping = $this->storage->getTableMapping();
     if (array_intersect(array_keys($schema['columns']), $table_mapping->getReservedColumns())) {
       throw new FieldException(format_string('Illegal field column names on @field_name', array('@field_name' => $storage_definition->getName())));
@@ -1609,6 +1621,10 @@ protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $stor
     foreach ($schema['columns'] as $column_name => $attributes) {
       $real_name = $table_mapping->getFieldColumnName($storage_definition, $column_name);
       $data_schema['fields'][$real_name] = $attributes;
+      // A dedicated table only contain rows for actual field values, and no
+      // rows for entities where the field is empty. Thus, we can safely
+      // enforce 'not null' on the columns for the field's required properties.
+      $data_schema['fields'][$real_name]['not null'] = $properties[$column_name]->isRequired();
     }
 
     // Add indexes.
diff --git a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php
index 3d1e33e..ee45c7d 100644
--- a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php
+++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php
@@ -27,12 +27,12 @@ public function referencedEntities() {
     // "autocreate" entities that are already populated in $item->entity.
     $target_entities = $ids = array();
     foreach ($this->list as $delta => $item) {
-      if ($item->target_id !== NULL) {
-        $ids[$delta] = $item->target_id;
-      }
-      elseif ($item->hasNewEntity()) {
+      if ($item->hasNewEntity()) {
         $target_entities[$delta] = $item->entity;
       }
+      elseif ($item->target_id !== NULL) {
+        $ids[$delta] = $item->target_id;
+      }
     }
 
     // Load and add the existing entities.
diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
index 8376d29..1698b77 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
@@ -159,13 +159,21 @@ public function isDisplayConfigurable($display_context);
   public function getDisplayOptions($display_context);
 
   /**
-   * Returns whether at least one non-empty item is required for this field.
+   * Returns whether the field can be empty.
    *
-   * Currently, required-ness is only enforced at the Form API level in entity
-   * edit forms, not during direct API saves.
+   * If a field is required, an entity needs to have at least a valid,
+   * non-empty item in that field's FieldItemList in order to pass validation.
+   *
+   * An item is considered empty if its isEmpty() method returns TRUE.
+   * Typically, that is if at least one of its required properties is empty.
    *
    * @return bool
    *   TRUE if the field is required.
+   *
+   * @see \Drupal\Core\TypedData\Plugin\DataType\ItemList::isEmpty()
+   * @see \Drupal\Core\Field\FieldItemInterface::isEmpty()
+   * @see \Drupal\Core\TypedData\DataDefinitionInterface:isRequired()
+   * @see \Drupal\Core\TypedData\TypedDataManager::getDefaultConstraints()
    */
   public function isRequired();
 
diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php
index 862b9e5..1d0de29 100644
--- a/core/lib/Drupal/Core/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php
@@ -28,6 +28,9 @@
   /**
    * Defines field item properties.
    *
+   * Properties that are required to constitute a valid, non-empty item should
+   * be denoted with \Drupal\Core\TypedData\DataDefinition::setRequired().
+   *
    * @return \Drupal\Core\TypedData\DataDefinitionInterface[]
    *   An array of property definitions of contained properties, keyed by
    *   property name.
@@ -67,10 +70,12 @@ public static function mainPropertyName();
    *   following key/value pairs:
    *   - columns: An array of Schema API column specifications, keyed by column
    *     name. The columns need to be a subset of the properties defined in
-   *     propertyDefinitions(). It is recommended to avoid having the column
-   *     definitions depend on field settings when possible. No assumptions
-   *     should be made on how storage engines internally use the original
-   *     column name to structure their storage.
+   *     propertyDefinitions(). The 'not null' property is ignored if present,
+   *     as it is determined automatically by the storage controller depending
+   *     on the table layout and the property definitions. It is recommended to
+   *     avoid having the column definitions depend on field settings when
+   *     possible. No assumptions should be made on how storage engines
+   *     internally use the original column name to structure their storage.
    *   - unique keys: (optional) An array of Schema API unique key definitions.
    *     Only columns that appear in the 'columns' array are allowed.
    *   - indexes: (optional) An array of Schema API index definitions. Only
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
index 2fb8242..1baf7bd 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
@@ -43,7 +43,8 @@ public static function defaultStorageSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('boolean')
-      ->setLabel(t('Boolean value'));
+      ->setLabel(t('Boolean value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -57,7 +58,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'int',
           'size' => 'tiny',
-          'not null' => TRUE,
         ),
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
index 1e241f9..b46cfc7 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
@@ -41,7 +41,8 @@ public static function defaultStorageSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('Decimal value'));
+      ->setLabel(t('Decimal value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -56,7 +57,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
           'type' => 'numeric',
           'precision' => $field_definition->getSetting('precision'),
           'scale' => $field_definition->getSetting('scale'),
-          'not null' => FALSE
         )
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
index 1821030..48bef3a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
@@ -32,7 +32,8 @@ class EmailItem extends FieldItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('email')
-      ->setLabel(t('E-mail'));
+      ->setLabel(t('E-mail'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -46,7 +47,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => Email::EMAIL_MAX_LENGTH,
-          'not null' => FALSE,
         ),
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
index aa97891..946645d 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -11,8 +11,8 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\TypedData\EntityDataDefinition;
 use Drupal\Core\Field\FieldDefinitionInterface;
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\TypedData\DataReferenceDefinition;
 
@@ -37,6 +37,13 @@
 class EntityReferenceItem extends FieldItemBase {
 
   /**
+   * Marker value to identify a newly created entity.
+   *
+   * @var int
+   */
+  protected static $NEW_ENTITY_MARKER = -1;
+
+  /**
    * {@inheritdoc}
    */
   public static function defaultStorageSettings() {
@@ -73,7 +80,9 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
       $target_id_definition = DataDefinition::create('string')
         ->setLabel(t('@label ID', array($target_type_info->getLabel())));
     }
+    $target_id_definition->setRequired(TRUE);
     $properties['target_id'] = $target_id_definition;
+
     $properties['entity'] = DataReferenceDefinition::create('entity')
       ->setLabel($target_type_info->getLabel())
       ->setDescription(t('The referenced entity'))
@@ -109,7 +118,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
           'description' => 'The ID of the target entity.',
           'type' => 'int',
           'unsigned' => TRUE,
-          'not null' => TRUE,
         ),
       );
     }
@@ -155,8 +163,12 @@ public function setValue($values, $notify = TRUE) {
         $this->onChange('entity', FALSE);
       }
       elseif (isset($values['target_id']) && isset($values['entity'])) {
-        // If both properties are passed, verify the passed values match.
-        if ($this->get('entity')->getTargetIdentifier() != $values['target_id']) {
+        // If both properties are passed, verify the passed values match. The
+        // only exception we allow is when we have a new entity: in this case
+        // its actual id and target_id will be different, due to the new entity
+        // marker.
+        $entity_id = $this->get('entity')->getTargetIdentifier();
+        if ($entity_id != $values['target_id'] && ($values['target_id'] != static::$NEW_ENTITY_MARKER || !$this->entity->isNew())) {
           throw new \InvalidArgumentException('The target id and entity passed to the entity reference item do not match.');
         }
       }
@@ -187,11 +199,13 @@ public function getValue() {
    */
   public function onChange($property_name, $notify = TRUE) {
     // Make sure that the target ID and the target property stay in sync.
-    if ($property_name == 'target_id') {
-      $this->writePropertyValue('entity', $this->target_id);
+    if ($property_name == 'entity') {
+      $property = $this->get('entity');
+      $target_id = $property->isTargetNew() ? static::$NEW_ENTITY_MARKER : $property->getTargetIdentifier();
+      $this->writePropertyValue('target_id', $target_id);
     }
-    elseif ($property_name == 'entity') {
-      $this->writePropertyValue('target_id', $this->get('entity')->getTargetIdentifier());
+    elseif ($property_name == 'target_id' && $this->target_id != static::$NEW_ENTITY_MARKER) {
+      $this->writePropertyValue('entity', $this->target_id);
     }
     parent::onChange($property_name, $notify);
   }
@@ -215,13 +229,12 @@ public function isEmpty() {
    */
   public function preSave() {
     if ($this->hasNewEntity()) {
-      $this->entity->save();
-    }
-    // Handle the case where an unsaved entity was directly set using the public
-    // 'entity' property and then saved before this entity. In this case
-    // ::hasNewEntity() will return FALSE but $this->target_id will still be
-    // empty.
-    if (empty($this->target_id) && $this->entity) {
+      // Save the entity if it has not already been saved by some other code.
+      if ($this->entity->isNew()) {
+        $this->entity->save();
+      }
+      // Make sure the parent knows we are updating this property so it can
+      // react properly.
       $this->target_id = $this->entity->id();
     }
   }
@@ -249,7 +262,7 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin
    *   TRUE if the item holds an unsaved entity.
    */
   public function hasNewEntity() {
-    return $this->target_id === NULL && ($entity = $this->entity) && $entity->isNew();
+    return $this->target_id === static::$NEW_ENTITY_MARKER;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php
index 038d4e1..695e40b 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php
@@ -29,7 +29,8 @@ class FloatItem extends NumericItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('float')
-      ->setLabel(t('Float'));
+      ->setLabel(t('Float'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -42,7 +43,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
       'columns' => array(
         'value' => array(
           'type' => 'float',
-          'not null' => FALSE,
         ),
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
index a2f569b..b1c9fa1 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
@@ -53,7 +53,8 @@ public static function defaultFieldSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('integer')
-      ->setLabel(t('Integer value'));
+      ->setLabel(t('Integer value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -92,7 +93,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
       'columns' => array(
         'value' => array(
           'type' => 'int',
-          'not null' => FALSE,
           // Expose the 'unsigned' setting in the field item schema.
           'unsigned' => $field_definition->getSetting('unsigned'),
           // Expose the 'size' setting in the field item schema. For instance,
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
index 851b818..45cd3f6 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
@@ -35,7 +35,8 @@ class LanguageItem extends FieldItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('Language code'));
+      ->setLabel(t('Language code'))
+      ->setRequired(TRUE);
 
     $properties['language'] = DataReferenceDefinition::create('language')
       ->setLabel(t('Language object'))
@@ -56,7 +57,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => 12,
-          'not null' => FALSE,
         ),
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
index c7641ff..7d844cc 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
@@ -43,7 +43,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => (int) $field_definition->getSetting('max_length'),
-          'not null' => FALSE,
           'binary' => $field_definition->getSetting('case_sensitive'),
         ),
       ),
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItemBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItemBase.php
index 2a587ed..4772983 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItemBase.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItemBase.php
@@ -34,7 +34,8 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
     // early t() calls by using the TranslationWrapper.
     $properties['value'] = DataDefinition::create('string')
       ->setLabel(new TranslationWrapper('Text value'))
-      ->setSetting('case_sensitive', $field_definition->getSetting('case_sensitive'));
+      ->setSetting('case_sensitive', $field_definition->getSetting('case_sensitive'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
index d355287..2dafed5 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
@@ -40,7 +40,8 @@ class TimestampItem extends FieldItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('timestamp')
-      ->setLabel(t('Timestamp value'));
+      ->setLabel(t('Timestamp value'))
+      ->setRequired(TRUE);
     return $properties;
   }
 
@@ -52,7 +53,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
       'columns' => array(
         'value' => array(
           'type' => 'int',
-          'not null' => FALSE,
         ),
       ),
     );
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
index 7a81f40..1afd100 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/UriItem.php
@@ -42,7 +42,8 @@ public static function defaultStorageSettings() {
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('uri')
       ->setLabel(t('URI value'))
-      ->setSetting('case_sensitive', $field_definition->getSetting('case_sensitive'));
+      ->setSetting('case_sensitive', $field_definition->getSetting('case_sensitive'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -56,7 +57,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => (int) $field_definition->getSetting('max_length'),
-          'not null' => TRUE,
           'binary' => $field_definition->getSetting('case_sensitive'),
         ),
       ),
diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
index 12b930e..1b9aaa5 100644
--- a/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
+++ b/core/lib/Drupal/Core/TypedData/DataReferenceBase.php
@@ -61,4 +61,5 @@ public function setValue($value, $notify = TRUE) {
   public function getString() {
     return (string) $this->getType() . ':' . $this->getTargetIdentifier();
   }
+
 }
diff --git a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
index 93274a5..24293f9 100644
--- a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
+++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
@@ -55,7 +55,8 @@ public static function defaultFieldSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['status'] = DataDefinition::create('integer')
-      ->setLabel(t('Comment status'));
+      ->setLabel(t('Comment status'))
+      ->setRequired(TRUE);
 
     $properties['cid'] = DataDefinition::create('integer')
       ->setLabel(t('Last comment ID'));
@@ -87,7 +88,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'status' => array(
           'description' => 'Whether comments are allowed on this entity: 0 = no, 1 = closed (read only), 2 = open (read/write).',
           'type' => 'int',
-          'not null' => TRUE,
           'default' => 0,
         ),
       ),
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index 6ecf319..a7dd1c3 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -51,7 +51,8 @@ public static function defaultStorageSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('datetime_iso8601')
-      ->setLabel(t('Date value'));
+      ->setLabel(t('Date value'))
+      ->setRequired(TRUE);
 
     $properties['date'] = DataDefinition::create('any')
       ->setLabel(t('Computed date'))
@@ -73,7 +74,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
           'description' => 'The date value.',
           'type' => 'varchar',
           'length' => 20,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
index c77245c..4972eee 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
@@ -73,10 +74,7 @@ public function elementValidate($element, FormStateInterface $form_state, $form)
         elseif ($auto_create && (count($this->getSelectionHandlerSetting('target_bundles')) == 1 || count($bundles) == 1)) {
           // Auto-create item. See
           // \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave().
-          $value[] = array(
-            'target_id' => NULL,
-            'entity' => $this->createNewEntity($input, $element['#autocreate_uid']),
-          );
+          $value[] = array('entity' => $this->createNewEntity($input, $element['#autocreate_uid']));
         }
       }
     };
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
index e9a0cf8..b8b8fcd 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
@@ -71,7 +72,6 @@ public function elementValidate($element, FormStateInterface $form_state, $form)
         // Auto-create item. See
         // \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave().
         $value = array(
-          'target_id' => NULL,
           'entity' => $this->createNewEntity($element['#value'], $element['#autocreate_uid']),
           // Keep the weight property.
           '_weight' => $element['#weight'],
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php
index 0587e93..dfddd05 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceFieldTest.php
@@ -8,9 +8,14 @@
 namespace Drupal\entity_reference\Tests;
 
 use Drupal\config\Tests\SchemaCheckTestTrait;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\system\Tests\Entity\EntityUnitTestBase;
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\user\Entity\Role;
+use Drupal\user\Entity\User;
+use Drupal\user\RoleInterface;
+use Drupal\user\UserInterface;
 
 /**
  * Tests for the entity reference field.
@@ -53,7 +58,7 @@ class EntityReferenceFieldTest extends EntityUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('entity_reference');
+  public static $modules = array('entity_reference', 'entity_reference_test');
 
   protected function setUp() {
     parent::setUp();
@@ -206,4 +211,136 @@ public function testReferencedEntitiesStringId() {
     $this->assertEqual($entities[0]->id(), $target_entity->id());
   }
 
+  /**
+   * Tests all the possible ways to autocreate an entity via the API.
+   */
+  function testAutocreateApi() {
+    $entity = $this->entityManager
+      ->getStorage($this->entityType)
+      ->create(array('name' => $this->randomString()));
+
+    // Test content entity autocreation.
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->set('user_id', $user);
+    });
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->set('user_id', $user, FALSE);
+    });
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->user_id->setValue($user);
+    });
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->user_id[0]->get('entity')->setValue($user);
+      $entity->user_id[0]->get('target_id')->setValue(-1);
+    });
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->user_id->setValue(array('entity' => $user, 'target_id' => -1));
+    });
+    try {
+      $message = 'Setting both the entity and an invalid target_id property fails.';
+      $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+        $user->save();
+        $entity->user_id->setValue(array('entity' => $user, 'target_id' => -1));
+      });
+      $this->fail($message);
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->pass($message);
+    }
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->user_id = $user;
+    });
+    $this->assertUserAutocreate($entity, function(EntityInterface $entity, UserInterface $user) {
+      $entity->user_id->entity = $user;
+    });
+
+    // Test config entity autocreation.
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->set('user_role', $role);
+    });
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->set('user_role', $role, FALSE);
+    });
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->user_role->setValue($role);
+    });
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->user_role[0]->get('entity')->setValue($role);
+      $entity->user_role[0]->get('target_id')->setValue(-1);
+    });
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->user_role->setValue(array('entity' => $role, 'target_id' => -1));
+    });
+    try {
+      $message = 'Setting both the entity and an invalid target_id property fails.';
+      $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+        $role->save();
+        $entity->user_role->setValue(array('entity' => $role, 'target_id' => -1));
+      });
+      $this->fail($message);
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->pass($message);
+    }
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->user_role = $role;
+    });
+    $this->assertUserRoleAutocreate($entity, function(EntityInterface $entity, RoleInterface $role) {
+      $entity->user_role->entity = $role;
+    });
+
+    // Test target entity saving after setting it as new.
+    $storage = $this->entityManager->getStorage('user');
+    $user_id = $this->generateRandomEntityId();
+    $user = $storage->create(array('uid' => $user_id, 'name' => $this->randomString()));
+    $entity->user_id = $user;
+    $user->save();
+    $entity->save();
+    $this->assertEqual($entity->user_id->target_id, $user->id());
+  }
+
+  /**
+   * Asserts that the setter callback performs autocreation for users.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The referencing entity.
+   * @param $setter_callback
+   *   A callback setting the target entity on the referencing entity.
+   *
+   * @return bool
+   *   TRUE if the user was autocreated, FALSE otherwise.
+   */
+  protected function assertUserAutocreate(EntityInterface $entity, $setter_callback) {
+    $storage = $this->entityManager->getStorage('user');
+    $user_id = $this->generateRandomEntityId();
+    $user = $storage->create(array('uid' => $user_id, 'name' => $this->randomString()));
+    $setter_callback($entity, $user);
+    $entity->save();
+    $storage->resetCache();
+    $user = User::load($user_id);
+    return $this->assertEqual($entity->user_id->target_id, $user->id());
+  }
+
+  /**
+   * Asserts that the setter callback performs autocreation for user roles.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The referencing entity.
+   * @param $setter_callback
+   *   A callback setting the target entity on the referencing entity.
+   *
+   * @return bool
+   *   TRUE if the user was autocreated, FALSE otherwise.
+   */
+  protected function assertUserRoleAutocreate(EntityInterface $entity, $setter_callback) {
+    $storage = $this->entityManager->getStorage('user_role');
+    $role_id = $this->generateRandomEntityId(TRUE);
+    $role = $storage->create(array('id' => $role_id, 'label' => $this->randomString()));
+    $setter_callback($entity, $role);
+    $entity->save();
+    $storage->resetCache();
+    $role = Role::load($role_id);
+    return $this->assertEqual($entity->user_role->target_id, $role->id());
+  }
+
 }
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module b/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module
index 2013fd1..51b506b 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test/entity_reference_test.module
@@ -6,6 +6,24 @@
  */
 
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+
+/**
+ * Implements hook_entity_base_field_info().
+ */
+function entity_reference_test_entity_base_field_info(EntityTypeInterface $entity_type) {
+  $fields = array();
+
+  if ($entity_type->id() === 'entity_test') {
+    $fields['user_role'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('User role'))
+      ->setDescription(t('The role of the associated user.'))
+      ->setSetting('target_type', 'user_role')
+      ->setSetting('handler', 'default');
+  }
+
+  return $fields;
+}
 
 /**
  * Implements hook_entity_base_field_info_alter().
diff --git a/core/modules/field/src/Tests/Number/NumberFieldTest.php b/core/modules/field/src/Tests/Number/NumberFieldTest.php
index 0c146ea..ded9c22 100644
--- a/core/modules/field/src/Tests/Number/NumberFieldTest.php
+++ b/core/modules/field/src/Tests/Number/NumberFieldTest.php
@@ -169,7 +169,6 @@ function testNumberIntegerField() {
       'columns' => array(
         'value' => array(
           'type' => 'int',
-          'not null' => FALSE,
           'unsigned' => '',
           'size' => 'normal'
         ),
diff --git a/core/modules/field/src/Tests/TestItemTest.php b/core/modules/field/src/Tests/TestItemTest.php
index 6b41870..b282fd1 100644
--- a/core/modules/field/src/Tests/TestItemTest.php
+++ b/core/modules/field/src/Tests/TestItemTest.php
@@ -83,7 +83,6 @@ public function testTestItem() {
         'value' => array(
           'type' => 'int',
           'size' => 'medium',
-          'not null' => FALSE,
         ),
       ),
       'unique keys' => array(),
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/HiddenTestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/HiddenTestItem.php
index b145abe..bbac229 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/HiddenTestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/HiddenTestItem.php
@@ -24,14 +24,4 @@
  */
 class HiddenTestItem extends TestItem {
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
-    $properties['value'] = DataDefinition::create('integer')
-      ->setLabel(t('Test integer value'));
-
-    return $properties;
-  }
-
 }
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
index 456f911..ddfe207 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
@@ -50,7 +50,8 @@ public static function defaultFieldSettings() {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('integer')
-      ->setLabel(t('Test integer value'));
+      ->setLabel(t('Test integer value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -64,7 +65,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'int',
           'size' => 'medium',
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index d1ae4f6..7130623 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -275,7 +275,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
 
     $fields['status'] = BaseFieldDefinition::create('boolean')
       ->setLabel(t('Status'))
-      ->setDescription(t('The status of the file, temporary (FALSE) and permanent (TRUE).'));
+      ->setDescription(t('The status of the file, temporary (FALSE) and permanent (TRUE).'))
+      ->setDefaultValue(FALSE);
 
     $fields['created'] = BaseFieldDefinition::create('created')
       ->setLabel(t('Created'))
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index 1c00e76..48c94ed 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -64,7 +64,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'target_id' => array(
           'description' => 'The ID of the file entity.',
           'type' => 'int',
-          'not null' => TRUE,
           'unsigned' => TRUE,
         ),
         'display' => array(
@@ -72,13 +71,11 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
           'type' => 'int',
           'size' => 'tiny',
           'unsigned' => TRUE,
-          'not null' => TRUE,
           'default' => 1,
         ),
         'description' => array(
           'description' => 'A description of the file.',
           'type' => 'text',
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index 6d1c149..d5f4269 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -96,20 +96,17 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'target_id' => array(
           'description' => 'The ID of the file entity.',
           'type' => 'int',
-          'not null' => TRUE,
           'unsigned' => TRUE,
         ),
         'alt' => array(
           'description' => "Alternative image text, for the image's 'alt' attribute.",
           'type' => 'varchar',
           'length' => 512,
-          'not null' => FALSE,
         ),
         'title' => array(
           'description' => "Image title text, for the image's 'title' attribute.",
           'type' => 'varchar',
           'length' => 1024,
-          'not null' => FALSE,
         ),
         'width' => array(
           'description' => 'The width of the image in pixels.',
diff --git a/core/modules/language/src/Tests/EntityDefaultLanguageTest.php b/core/modules/language/src/Tests/EntityDefaultLanguageTest.php
index fa1a759..b3b109a 100644
--- a/core/modules/language/src/Tests/EntityDefaultLanguageTest.php
+++ b/core/modules/language/src/Tests/EntityDefaultLanguageTest.php
@@ -31,6 +31,8 @@ class EntityDefaultLanguageTest extends KernelTestBase {
   public function setUp() {
     parent::setUp();
 
+    $this->installEntitySchema('user');
+
     // Activate Spanish language, so there are two languages activated.
     $language = $this->container->get('entity.manager')->getStorage('configurable_language')->create(array(
       'id' => 'es',
diff --git a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
index 37e40d4..1b347aa 100644
--- a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
+++ b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
@@ -72,32 +72,27 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
           'description' => 'The URL of the link.',
           'type' => 'varchar',
           'length' => 2048,
-          'not null' => FALSE,
         ),
         'title' => array(
           'description' => 'The link text.',
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
         'route_name' => array(
           'description' => 'The machine name of a defined Route this link represents.',
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
         'route_parameters' => array(
           'description' => 'Serialized array of route parameters of the link.',
           'type' => 'blob',
           'size' => 'big',
-          'not null' => FALSE,
           'serialize' => TRUE,
         ),
         'options' => array(
           'description' => 'Serialized array of options for the link.',
           'type' => 'blob',
           'size' => 'big',
-          'not null' => FALSE,
           'serialize' => TRUE,
         ),
       ),
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 4b7671f..6d618be 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -444,6 +444,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setDescription(t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'))
       ->setRevisionable(TRUE)
       ->setTranslatable(TRUE)
+      ->setDefaultValue(FALSE)
       ->setDisplayOptions('form', array(
         'type' => 'boolean_checkbox',
         'settings' => array(
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php
index 6fa8fbe..160dce0 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php
@@ -28,7 +28,8 @@ class ListFloatItem extends ListItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('float')
-      ->setLabel(t('Float value'));
+      ->setLabel(t('Float value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -41,7 +42,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
       'columns' => array(
         'value' => array(
           'type' => 'float',
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php
index 8a0b297..afda838 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php
@@ -28,7 +28,8 @@ class ListIntegerItem extends ListItemBase {
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('integer')
-      ->setLabel(t('Integer value'));
+      ->setLabel(t('Integer value'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -41,7 +42,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
       'columns' => array(
         'value' => array(
           'type' => 'int',
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php
index d74049a..a95c8e8 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php
@@ -30,7 +30,8 @@ class ListStringItem extends ListItemBase {
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
       ->setLabel(t('Text value'))
-      ->addConstraint('Length', array('max' => 255));
+      ->addConstraint('Length', array('max' => 255))
+      ->setRequired(TRUE);
 
     return $properties;
   }
@@ -44,7 +45,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/shortcut/src/ShortcutPathItem.php b/core/modules/shortcut/src/ShortcutPathItem.php
index 8ad82d3..7c63a30 100644
--- a/core/modules/shortcut/src/ShortcutPathItem.php
+++ b/core/modules/shortcut/src/ShortcutPathItem.php
@@ -23,7 +23,8 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
     $properties['value'] = DataDefinition::create('string')
       ->setLabel(t('String value'))
       ->setComputed(TRUE)
-      ->setClass('\Drupal\shortcut\ShortcutPathValue');
+      ->setClass('\Drupal\shortcut\ShortcutPathValue')
+      ->setRequired(TRUE);
     return $properties;
   }
 
diff --git a/core/modules/system/src/Tests/Entity/BundleConstraintValidatorTest.php b/core/modules/system/src/Tests/Entity/BundleConstraintValidatorTest.php
index be2dc48..6886e29 100644
--- a/core/modules/system/src/Tests/Entity/BundleConstraintValidatorTest.php
+++ b/core/modules/system/src/Tests/Entity/BundleConstraintValidatorTest.php
@@ -29,6 +29,7 @@ class BundleConstraintValidatorTest extends KernelTestBase {
 
   protected function setUp() {
     parent::setUp();
+    $this->installEntitySchema('user');
     $this->typedData = $this->container->get('typed_data_manager');
   }
 
diff --git a/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php
index 84a25af..3cc8b3a 100644
--- a/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\system\Tests\Entity;
 
+use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\Core\Entity\EntityTypeEvents;
 use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldStorageDefinitionEvents;
+use Drupal\Core\Language\LanguageInterface;
 use Drupal\entity_test\FieldStorageDefinition;
 
 /**
@@ -236,14 +238,16 @@ public function testBundleFieldCreateUpdateDeleteWithoutData() {
   public function testBaseFieldCreateDeleteWithExistingEntities() {
     // Save an entity.
     $name = $this->randomString();
-    $entity = $this->entityManager->getStorage('entity_test_update')->create(array('name' => $name));
+    $storage = $this->entityManager->getStorage('entity_test_update');
+    $entity = $storage->create(array('name' => $name));
     $entity->save();
 
     // Add a base field and run the update. Ensure the base field's column is
     // created and the prior saved entity data is still there.
     $this->addBaseField();
     $this->entityDefinitionUpdateManager->applyUpdates();
-    $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Column created in shared table for new_base_field.');
+    $schema_handler = $this->database->schema();
+    $this->assertTrue($schema_handler->fieldExists('entity_test_update', 'new_base_field'), 'Column created in shared table for new_base_field.');
     $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id());
     $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field creation.');
 
@@ -251,9 +255,33 @@ public function testBaseFieldCreateDeleteWithExistingEntities() {
     // is deleted and the prior saved entity data is still there.
     $this->removeBaseField();
     $this->entityDefinitionUpdateManager->applyUpdates();
-    $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Column deleted from shared table for new_base_field.');
+    $this->assertFalse($schema_handler->fieldExists('entity_test_update', 'new_base_field'), 'Column deleted from shared table for new_base_field.');
     $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id());
     $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field deletion.');
+
+    // Add a base field with a 'not null' column in the schema and run the
+    // update. Ensure 'not null' is not applied and thus no exception is thrown.
+    $this->addBaseField('shape_required');
+    $this->entityDefinitionUpdateManager->applyUpdates();
+    $assert = $schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && $schema_handler->fieldExists('entity_test_update', 'new_base_field__color');
+    $this->assertTrue($assert, 'Columns created in shared table for new_base_field.');
+
+    // Recreate the field after emptying the base table and check that its
+    // columns are not 'not null'.
+    // @todo Revisit this test when allowing for required storage field
+    //   definitions. See https://www.drupal.org/node/2390495.
+    $entity->delete();
+    $this->removeBaseField();
+    $this->entityDefinitionUpdateManager->applyUpdates();
+    $assert = !$schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && !$schema_handler->fieldExists('entity_test_update', 'new_base_field__color');
+    $this->assert($assert, 'Columns removed from the shared table for new_base_field.');
+    $this->addBaseField('shape_required');
+    $this->entityDefinitionUpdateManager->applyUpdates();
+    $assert = $schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && $schema_handler->fieldExists('entity_test_update', 'new_base_field__color');
+    $this->assertTrue($assert, 'Columns created again in shared table for new_base_field.');
+    $entity = $storage->create(array('name' => $name));
+    $entity->save();
+    $this->pass('The new_base_field columns are still nullable');
   }
 
   /**
@@ -267,14 +295,16 @@ public function testBaseFieldCreateDeleteWithExistingEntities() {
   public function testBundleFieldCreateDeleteWithExistingEntities() {
     // Save an entity.
     $name = $this->randomString();
-    $entity = $this->entityManager->getStorage('entity_test_update')->create(array('name' => $name));
+    $storage = $this->entityManager->getStorage('entity_test_update');
+    $entity = $storage->create(array('name' => $name));
     $entity->save();
 
     // Add a bundle field and run the update. Ensure the bundle field's table
     // is created and the prior saved entity data is still there.
     $this->addBundleField();
     $this->entityDefinitionUpdateManager->applyUpdates();
-    $this->assertTrue($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.');
+    $schema_handler = $this->database->schema();
+    $this->assertTrue($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.');
     $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id());
     $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field creation.');
 
@@ -282,9 +312,31 @@ public function testBundleFieldCreateDeleteWithExistingEntities() {
     // table is deleted and the prior saved entity data is still there.
     $this->removeBundleField();
     $this->entityDefinitionUpdateManager->applyUpdates();
-    $this->assertFalse($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.');
+    $this->assertFalse($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.');
     $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id());
     $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field deletion.');
+
+    // Test that required columns are created as 'not null'.
+    $this->addBundleField('shape_required');
+    $this->entityDefinitionUpdateManager->applyUpdates();
+    $message = 'The new_bundle_field_shape column is not nullable.';
+    try {
+      $this->database->insert('entity_test_update__new_bundle_field')
+        ->fields(array(
+          'bundle' => $entity->bundle(),
+          'deleted'=> 0,
+          'entity_id' => $entity->id(),
+          'revision_id' => $entity->id(),
+          'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
+          'delta' => 0,
+          'new_bundle_field_color' => $this->randomString(),
+        ))
+        ->execute();
+      $this->fail($message);
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      $this->pass($message);
+    }
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php
index 485aafc..73b9a89 100644
--- a/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/src/Tests/Entity/EntityUnitTestBase.php
@@ -30,6 +30,13 @@
   protected $entityManager;
 
   /**
+   * A list of generated identifiers.
+   *
+   * @var array
+   */
+  protected $generatedIds = array();
+
+  /**
    * The state service.
    *
    * @var \Drupal\Core\State\StateInterface
@@ -160,4 +167,23 @@ protected function refreshServices() {
     $this->state = $this->container->get('state');
   }
 
+  /**
+   * Generates a random ID avoiding collisions.
+   *
+   * @param bool $string
+   *   (optional) Whether the id should have string type. Defaults to FALSE.
+   *
+   * @return int|string
+   *   The entity identifier.
+   */
+  protected function generateRandomEntityId($string = FALSE) {
+    srand(time());
+    do {
+      $id = $string ? $this->randomMachineName() : mt_rand(1, 0xFFFFFFFF);
+    }
+    while (isset($this->generatedIds[$id]));
+    $this->generatedIds[$id] = $id;
+    return $id;
+  }
+
 }
diff --git a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php
index c7dab96..5b04cd5 100644
--- a/core/modules/system/src/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/src/Tests/Plugin/ContextPluginTest.php
@@ -25,6 +25,8 @@ class ContextPluginTest extends KernelTestBase {
    * Tests basic context definition and value getters and setters.
    */
   function testContext() {
+    $this->installEntitySchema('user');
+
     $name = $this->randomMachineName();
     $manager = new MockBlockManager();
     $plugin = $manager->createInstance('user_name');
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php
index 4dc8196..e7bbd35 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItem.php
@@ -65,12 +65,10 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'shape' => array(
           'type' => 'varchar',
           'length' => 32,
-          'not null' => FALSE,
         ),
         'color' => array(
           'type' => 'varchar',
           'length' => 32,
-          'not null' => FALSE,
         ),
       ),
     ) + $foreign_keys;
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItemRequired.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItemRequired.php
new file mode 100644
index 0000000..428efed
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldType/ShapeItemRequired.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity_test\Plugin\Field\FieldType\ShapeItemRequired.
+ */
+
+namespace Drupal\entity_test\Plugin\Field\FieldType;
+
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+
+/**
+ * Defines the 'shape_required' field type.
+ *
+ * @FieldType(
+ *   id = "shape_required",
+ *   label = @Translation("Shape (required)"),
+ *   description = @Translation("Yet another dummy field type."),
+ * )
+ */
+class ShapeItemRequired extends ShapeItem {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
+    $properties = parent::propertyDefinitions($field_definition);
+    $properties['shape']->setRequired(TRUE);
+    return $properties;
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index f14eb91..d94e2bf 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Component\Utility\String;
+use Drupal\taxonomy\Plugin\Field\FieldType\TaxonomyTermReferenceItem;
 
 /**
  * Plugin implementation of the 'taxonomy_term_reference_link' formatter.
@@ -31,7 +32,7 @@ public function viewElements(FieldItemListInterface $items) {
     // Terms without target_id do not exist yet, theme such terms as just their
     // name.
     foreach ($items as $delta => $item) {
-      if (!$item->target_id) {
+      if ($item->hasNewEntity()) {
         $elements[$delta] = array(
           '#markup' => String::checkPlain($item->entity->label()),
         );
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
index 83d9780..75051c9 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
@@ -68,8 +68,9 @@ public function getPossibleOptions(AccountInterface $account = NULL) {
   public function getSettableValues(AccountInterface $account = NULL) {
     // Flatten options firstly, because Settable Options may contain group
     // arrays.
-    $flatten_options = OptGroup::flattenOptions($this->getSettableOptions($account));
-    return array_keys($flatten_options);
+    $values = array_keys(OptGroup::flattenOptions($this->getSettableOptions($account)));
+    $values[] = static::$NEW_ENTITY_MARKER;
+    return $values;
   }
 
   /**
@@ -103,7 +104,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'target_id' => array(
           'type' => 'int',
           'unsigned' => TRUE,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
index dd85ed7..8b7fa81 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\Plugin\Field\FieldType\TaxonomyTermReferenceItem;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -156,7 +157,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface
           'vid' => $vocabulary->id(),
           'name' => $value,
         ));
-        $item = array('target_id' => NULL, 'entity' => $term);
+        $item = array('entity' => $term);
       }
       $items[] = $item;
     }
diff --git a/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php b/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
index 4fd6e0b..3a4d7a2 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
@@ -34,7 +34,6 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => 256,
-          'not null' => FALSE,
         ),
       ),
     );
@@ -45,7 +44,8 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('Telephone number'));
+      ->setLabel(t('Telephone number'))
+      ->setRequired(TRUE);
 
     return $properties;
   }
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
index 3792220..0b5fec9 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
@@ -41,12 +41,10 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'varchar',
           'length' => $field_definition->getSetting('max_length'),
-          'not null' => FALSE,
         ),
         'format' => array(
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
index 972b6e2..9a79fab 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php
@@ -23,7 +23,8 @@
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
     $properties['value'] = DataDefinition::create('string')
-      ->setLabel(t('Text'));
+      ->setLabel(t('Text'))
+      ->setRequired(TRUE);
 
     $properties['format'] = DataDefinition::create('filter_format')
       ->setLabel(t('Text format'));
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
index bf1054f..528d931 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
@@ -31,12 +31,10 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'text',
           'size' => 'big',
-          'not null' => FALSE,
         ),
         'format' => array(
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
index e0ba0c8..d3aeb6a 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
@@ -61,17 +61,14 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array(
           'type' => 'text',
           'size' => 'big',
-          'not null' => FALSE,
         ),
         'summary' => array(
           'type' => 'text',
           'size' => 'big',
-          'not null' => FALSE,
         ),
         'format' => array(
           'type' => 'varchar',
           'length' => 255,
-          'not null' => FALSE,
         ),
       ),
       'indexes' => array(
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
index a3a7013..b1d05a1 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
@@ -9,7 +9,6 @@
 
 use Drupal\Core\Entity\ContentEntityType;
 use Drupal\Core\Entity\Sql\DefaultTableMapping;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -257,72 +256,89 @@ public function testGetSchemaBase() {
             'description' => 'The name field.',
             'type' => 'varchar',
             'length' => 255,
+            'not null' => FALSE,
           ),
           'description__value' => array(
             'description' => 'The description field.',
             'type' => 'text',
+            'not null' => FALSE,
           ),
           'description__format' => array(
             'description' => 'The description field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'uuid' => array(
             'description' => 'The uuid field.',
             'type' => 'varchar',
             'length' => 128,
+            'not null' => FALSE,
           ),
           'hash' => array(
             'description' => 'The hash field.',
             'type' => 'varchar',
             'length' => 20,
+            'not null' => FALSE,
           ),
           'email__username' => array(
             'description' => 'The email field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'email__hostname' => array(
             'description' => 'The email field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'email__domain' => array(
             'description' => 'The email field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'owner' => array(
             'description' => 'The owner field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'translator' => array(
             'description' => 'The translator field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'location__country' => array(
             'description' => 'The location field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'location__state' => array(
             'description' => 'The location field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'location__city' => array(
             'description' => 'The location field.',
             'type' => 'varchar',
+            'not null' => FALSE,
           ),
           'editor' => array(
             'description' => 'The editor field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'editor_revision__target_id' => array(
             'description' => 'The editor_revision field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'editor_revision__target_revision_id' => array(
             'description' => 'The editor_revision field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'long_index_name' => array(
             'description' => 'The long_index_name field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'default_langcode' => array(
             'description' => 'Boolean indicating whether field values are in the default entity language.',
@@ -430,6 +446,7 @@ public function testGetSchemaRevisionable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'int',
+            'not null' => FALSE,
           )
         ),
         'primary key' => array('id'),
@@ -455,6 +472,7 @@ public function testGetSchemaRevisionable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'serial',
+            'not null' => TRUE,
           ),
         ),
         'primary key' => array('revision_id'),
@@ -632,6 +650,7 @@ public function testGetSchemaRevisionableTranslatable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'int',
+            'not null' => FALSE,
           ),
           'langcode' => array(
             'description' => 'The langcode field.',
@@ -662,6 +681,7 @@ public function testGetSchemaRevisionableTranslatable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'serial',
+            'not null' => TRUE,
           ),
           'langcode' => array(
             'description' => 'The langcode field.',
@@ -692,6 +712,7 @@ public function testGetSchemaRevisionableTranslatable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'int',
+            'not null' => TRUE,
           ),
           'langcode' => array(
             'description' => 'The langcode field.',
@@ -722,6 +743,7 @@ public function testGetSchemaRevisionableTranslatable() {
           'revision_id' => array(
             'description' => 'The revision_id field.',
             'type' => 'int',
+            'not null' => TRUE,
           ),
           'langcode' => array(
             'description' => 'The langcode field.',
@@ -1229,6 +1251,19 @@ public function setUpStorageDefinition($field_name, array $schema) {
     $this->storageDefinitions[$field_name]->expects($this->any())
       ->method('getColumns')
       ->will($this->returnValue($schema['columns']));
+    // Add property definitions.
+    if (!empty($schema['columns'])) {
+      $property_definitions = array();
+      foreach ($schema['columns'] as $column => $info) {
+        $property_definitions[$column] = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface');
+        $property_definitions[$column]->expects($this->any())
+          ->method('isRequired')
+          ->will($this->returnValue(!empty($info['not null'])));
+      }
+      $this->storageDefinitions[$field_name]->expects($this->any())
+        ->method('getPropertyDefinitions')
+        ->will($this->returnValue($property_definitions));
+    }
   }
 
 }
