diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php
new file mode 100644
index 0000000..ee9e632
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\Field\FieldType\ChangedItem.
+ */
+
+namespace Drupal\Core\Field\Plugin\Field\FieldType;
+
+/**
+ * Defines the 'changed' entity field type.
+ *
+ * @FieldType(
+ *   id = "changed",
+ *   label = @Translation("Last changed"),
+ *   description = @Translation("An entity field containing a UNIX timestamp of when the entity has been last updated."),
+ *   configurable = FALSE,
+ *   constraints = {
+ *     "ComplexData" = {"value" = {"EntityChanged" = {}}}
+ *   }
+ * )
+ */
+class ChangedItem extends CreatedItem {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave() {
+    parent::preSave();
+    $this->value = REQUEST_TIME;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php
new file mode 100644
index 0000000..2b332fc
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\Field\FieldType\CreatedItem.
+ */
+
+namespace Drupal\Core\Field\Plugin\Field\FieldType;
+
+/**
+ * Defines the 'created' entity field type.
+ *
+ * @FieldType(
+ *   id = "created",
+ *   label = @Translation("Created"),
+ *   description = @Translation("An entity field containing a UNIX timestamp of when the entity has been created."),
+ *   configurable = FALSE
+ * )
+ */
+class CreatedItem extends TimestampItem {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applyDefaultValue($notify = TRUE) {
+    parent::applyDefaultValue($notify);
+    // Created fields default to the current timestamp.
+    $this->setValue(array('value' => REQUEST_TIME), $notify);
+    return $this;
+  }
+
+}
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 58a5961..524ccd3 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -27,7 +27,7 @@
  *   label = @Translation("Entity reference"),
  *   description = @Translation("An entity field containing an entity reference."),
  *   configurable = FALSE,
- *   constraints = {"ValidReference" = TRUE}
+ *   constraints = {"ValidReference" = {}}
  * )
  */
 class EntityReferenceItem extends FieldItemBase {
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
new file mode 100644
index 0000000..1c5e49b
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Plugin\Field\FieldType\TimestampItem.
+ */
+
+namespace Drupal\Core\Field\Plugin\Field\FieldType;
+
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\TypedData\DataDefinition;
+
+/**
+ * Defines the 'timestamp' entity field type.
+ *
+ * @FieldType(
+ *   id = "timestamp",
+ *   label = @Translation("Timestamp"),
+ *   description = @Translation("An entity field containing a UNIX timestamp value."),
+ *   configurable = FALSE
+ * )
+ */
+class TimestampItem extends FieldItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function propertyDefinitions(FieldDefinitionInterface $field_definition) {
+    $properties['value'] = DataDefinition::create('timestamp')
+      ->setLabel(t('Timestamp value'));
+    return $properties;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function schema(FieldDefinitionInterface $field_definition) {
+    return array(
+      'columns' => array(
+        'value' => array(
+          'type' => 'int',
+          'not null' => FALSE,
+        ),
+      ),
+    );
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php
index f68ffc2..91740e5 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Email.php
@@ -17,7 +17,7 @@
  * @DataType(
  *   id = "email",
  *   label = @Translation("Email"),
- *   constraints = {"Email" = TRUE}
+ *   constraints = {"Email" = {}}
  * )
  */
 class Email extends String implements StringInterface {
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index ff77acb..1285587 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -401,10 +401,6 @@ public function getConstraints(DataDefinitionInterface $definition) {
     // Add in constraints specified by the data type.
     if (isset($type_definition['constraints'])) {
       foreach ($type_definition['constraints'] as $name => $options) {
-        // Annotations do not support empty arrays.
-        if ($options === TRUE) {
-          $options = array();
-        }
         $constraints[] = $validation_manager->create($name, $options);
       }
     }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php
index 6ed2d3a..fe3a1fb 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php
@@ -54,10 +54,10 @@ public function validate($value, Constraint $constraint) {
     }
     // @todo: Move those to separate constraint validators.
     try {
-      if ($typed_data instanceof DateTimeInterface && $typed_data->getDateTime()->hasErrors()) {
+      if ($typed_data instanceof DateTimeInterface && $typed_data->getDateTime() && $typed_data->getDateTime()->hasErrors()) {
         $valid = FALSE;
       }
-      if ($typed_data instanceof DurationInterface && !($typed_data->getDuration() instanceof \DateInterval)) {
+      if ($typed_data instanceof DurationInterface && $typed_data->getDuration() && !($typed_data->getDuration() instanceof \DateInterval)) {
         $valid = FALSE;
       }
     }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
index 3ade60e..a63916d 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Feed.php
@@ -147,13 +147,11 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Refresh'))
       ->setDescription(t('How often to check for new feed items, in seconds.'));
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['checked'] = FieldDefinition::create('integer')
+    $fields['checked'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Checked'))
       ->setDescription(t('Last time feed was checked for new items, as Unix timestamp.'));
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['queued'] = FieldDefinition::create('integer')
+    $fields['queued'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Queued'))
       ->setDescription(t('Time when this feed was queued for refresh, 0 if not queued.'));
 
@@ -177,8 +175,9 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Etag'))
       ->setDescription(t('Entity tag HTTP response header, used for validating cache.'));
 
-    // @todo Convert to a "changed" field in https://drupal.org/node/2145103.
-    $fields['modified'] = FieldDefinition::create('integer')
+    // This is updated by the fetcher and not when the feed is saved, therefore
+    // it's a timestamp and not a changed field.
+    $fields['modified'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Modified'))
       ->setDescription(t('When the feed was last modified, as a Unix timestamp.'));
 
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
index 191f5bc..ce5d356 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Entity/Item.php
@@ -49,17 +49,6 @@ public function label() {
   /**
    * {@inheritdoc}
    */
-  public function postCreate(EntityStorageControllerInterface $storage_controller) {
-    parent::postCreate($storage_controller);
-
-    if ($this->getPostedTime() === NULL) {
-      $this->setPostedTime(REQUEST_TIME);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public static function baseFieldDefinitions($entity_type) {
     $fields['iid'] = FieldDefinition::create('integer')
       ->setLabel(t('Aggregator item ID'))
@@ -92,8 +81,7 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Description'))
       ->setDescription(t('The body of the feed item.'));
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['timestamp'] = FieldDefinition::create('integer')
+    $fields['timestamp'] = FieldDefinition::create('created')
       ->setLabel(t('Posted timestamp'))
       ->setDescription(t('Posted date of the feed item, as a Unix timestamp.'));
 
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
index c2b0325..e565029 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
@@ -100,16 +100,6 @@ public function getTheme() {
   /**
    * {@inheritdoc}
    */
-  public function preSave(EntityStorageControllerInterface $storage_controller) {
-    parent::preSave($storage_controller);
-
-    // Before saving the custom block, set changed time.
-    $this->set('changed', REQUEST_TIME);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
     parent::postSave($storage_controller, $update);
 
@@ -196,11 +186,9 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Revision log message'))
       ->setDescription(t('The revision log message.'));
 
-    // @todo Convert to a "changed" field in https://drupal.org/node/2145103.
-    $fields['changed'] = FieldDefinition::create('integer')
+    $fields['changed'] = FieldDefinition::create('changed')
       ->setLabel(t('Changed'))
-      ->setDescription(t('The time that the custom block was last edited.'))
-      ->setPropertyConstraints('value', array('EntityChanged' => array()));
+      ->setDescription(t('The time that the custom block was last edited.'));
 
     return $fields;
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
index 321dfc4..c0bc40d 100644
--- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
@@ -132,12 +132,6 @@ public function preSave(EntityStorageControllerInterface $storage_controller) {
         } while (!\Drupal::lock()->acquire($lock_name));
         $this->threadLock = $lock_name;
       }
-      if (is_null($this->getCreatedTime())) {
-        $this->setCreatedTime(REQUEST_TIME);
-      }
-      if (is_null($this->getChangedTime())) {
-        $this->set('changed', $this->getCreatedTime());
-      }
       // We test the value with '===' because we need to modify anonymous
       // users as well.
       if ($this->getOwnerId() === \Drupal::currentUser()->id() && \Drupal::currentUser()->isAuthenticated()) {
@@ -273,16 +267,13 @@ public static function baseFieldDefinitions($entity_type) {
       ->setDescription(t("The comment author's hostname."))
       ->setSetting('max_length', 128);
 
-    // @todo Convert to a "created" field in https://drupal.org/node/2145103.
-    $fields['created'] = FieldDefinition::create('integer')
+    $fields['created'] = FieldDefinition::create('created')
       ->setLabel(t('Created'))
       ->setDescription(t('The time that the comment was created.'));
 
-    // @todo Convert to a "changed" field in https://drupal.org/node/2145103.
-    $fields['changed'] = FieldDefinition::create('integer')
+    $fields['changed'] = FieldDefinition::create('changed')
       ->setLabel(t('Changed'))
-      ->setDescription(t('The time that the comment was last edited.'))
-      ->setPropertyConstraints('value', array('EntityChanged' => array()));
+      ->setDescription(t('The time that the comment was last edited.'));
 
     $fields['status'] = FieldDefinition::create('boolean')
       ->setLabel(t('Publishing status'))
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php b/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
index f1c3ea5..b9b4904 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Access/ContentTranslationManageAccessCheck.php
@@ -45,7 +45,7 @@ public function access(Route $route, Request $request, AccountInterface $account
     if ($entity = $request->attributes->get($entity_type)) {
       $route_requirements = $route->getRequirements();
       $operation = $route_requirements['_access_content_translation_manage'];
-      $controller = content_translation_controller($entity_type);
+      $controller = content_translation_controller($entity_type, $account);
 
       // Load translation.
       $translations = $entity->getTranslationLanguages();
diff --git a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
index e930206..b4f4111 100644
--- a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
+++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\edit\Form;
 
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
@@ -226,17 +227,16 @@ protected function simplify(array &$form, array &$form_state) {
   /**
    * Finds the field name for the field carrying the changed timestamp, if any.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
    *   The entity.
    *
    * @return string|null
    *   The name of the field found or NULL if not found.
    */
-  protected function getChangedFieldName(EntityInterface $entity) {
-    foreach ($entity as $field_name => $field) {
-      $constraints = $field->getItemDefinition()->getConstraints();
-      if (isset($constraints['ComplexData']['value']['EntityChanged'])) {
-        return $field_name;
+  protected function getChangedFieldName(ContentEntityInterface $entity) {
+    foreach ($entity->getFieldDefinitions() as $field) {
+      if ($field->getType() == 'changed') {
+        return $field->getName();
       }
     }
   }
diff --git a/core/modules/file/lib/Drupal/file/Entity/File.php b/core/modules/file/lib/Drupal/file/Entity/File.php
index d74dee8..b45d4aa 100644
--- a/core/modules/file/lib/Drupal/file/Entity/File.php
+++ b/core/modules/file/lib/Drupal/file/Entity/File.php
@@ -201,19 +201,7 @@ public static function preCreate(EntityStorageControllerInterface $storage_contr
   public function preSave(EntityStorageControllerInterface $storage_controller) {
     parent::preSave($storage_controller);
 
-    $this->changed->value = REQUEST_TIME;
-    if (empty($this->created->value)) {
-      $this->created->value = REQUEST_TIME;
-    }
-
     $this->setSize(filesize($this->getFileUri()));
-    if (!isset($this->langcode->value)) {
-      // Default the file's language code to none, because files are language
-      // neutral more often than language dependent. Until we have better
-      // flexible settings.
-      // @todo See http://drupal.org/node/258785 and followups.
-      $this->langcode = Language::LANGCODE_NOT_SPECIFIED;
-    }
   }
 
   /**
@@ -280,11 +268,11 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Status'))
       ->setDescription(t('The status of the file, temporary (0) and permanent (1).'));
 
-    $fields['created'] = FieldDefinition::create('integer')
+    $fields['created'] = FieldDefinition::create('created')
       ->setLabel(t('Created'))
       ->setDescription(t('The timestamp that the file was created.'));
 
-    $fields['changed'] = FieldDefinition::create('integer')
+    $fields['changed'] = FieldDefinition::create('changed')
       ->setLabel(t('Changed'))
       ->setDescription(t('The timestamp that the file was last changed.'));
 
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index fcacb46..75c7e14 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -77,27 +77,6 @@ public function getRevisionId() {
   /**
    * {@inheritdoc}
    */
-  public static function preCreate(EntityStorageControllerInterface $storage_controller, array &$values) {
-    parent::preCreate($storage_controller, $values);
-    // @todo Handle this through property defaults.
-    if (empty($values['created'])) {
-      $values['created'] = REQUEST_TIME;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSave(EntityStorageControllerInterface $storage_controller) {
-    parent::preSave($storage_controller);
-
-    // Before saving the node, set changed and revision times.
-    $this->changed->value = REQUEST_TIME;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
     parent::preSaveRevision($storage_controller, $record);
 
@@ -413,16 +392,13 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Publishing status'))
       ->setDescription(t('A boolean indicating whether the node is published.'));
 
-    // @todo Convert to a "created" field in https://drupal.org/node/2145103.
-    $fields['created'] = FieldDefinition::create('integer')
+    $fields['created'] = FieldDefinition::create('created')
       ->setLabel(t('Created'))
       ->setDescription(t('The time that the node was created.'));
 
-    // @todo Convert to a "changed" field in https://drupal.org/node/2145103.
-    $fields['changed'] = FieldDefinition::create('integer')
+    $fields['changed'] = FieldDefinition::create('changed')
       ->setLabel(t('Changed'))
-      ->setDescription(t('The time that the node was last edited.'))
-      ->setPropertyConstraints('value', array('EntityChanged' => array()));
+      ->setDescription(t('The time that the node was last edited.'));
 
     $fields['promote'] = FieldDefinition::create('boolean')
       ->setLabel(t('Promote'))
@@ -432,8 +408,7 @@ public static function baseFieldDefinitions($entity_type) {
       ->setLabel(t('Sticky'))
       ->setDescription(t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.'));
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['revision_timestamp'] = FieldDefinition::create('integer')
+    $fields['revision_timestamp'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Revision timestamp'))
       ->setDescription(t('The time that the current revision was created.'))
       ->setQueryable(FALSE);
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
index e366b85..f84c058 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Term.php
@@ -173,16 +173,6 @@ public static function postDelete(EntityStorageControllerInterface $storage_cont
   /**
    * {@inheritdoc}
    */
-  public function preSave(EntityStorageControllerInterface $storage_controller) {
-    parent::preSave($storage_controller);
-
-    // Before saving the term, set changed time.
-    $this->changed->value = REQUEST_TIME;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
     parent::postSave($storage_controller, $update);
 
@@ -242,10 +232,9 @@ public static function baseFieldDefinitions($entity_type) {
       ->setSetting('default_value', 0)
       ->setConstraints(array('TermParent' => array()));
 
-    $fields['changed'] = FieldDefinition::create('integer')
+    $fields['changed'] = FieldDefinition::create('changed')
       ->setLabel(t('Changed'))
-      ->setDescription(t('The time that the term was last edited.'))
-      ->setPropertyConstraints('value', array('EntityChanged' => array()));
+      ->setDescription(t('The time that the term was last edited.'));
 
     return $fields;
   }
diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php
index 44bce77..9d316a7 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -71,9 +71,6 @@ public function isNew() {
   static function preCreate(EntityStorageControllerInterface $storage_controller, array &$values) {
     parent::preCreate($storage_controller, $values);
 
-    if (!isset($values['created'])) {
-      $values['created'] = REQUEST_TIME;
-    }
     // Users always have the authenticated user role.
     $values['roles'][] = DRUPAL_AUTHENTICATED_RID;
   }
@@ -487,19 +484,16 @@ public static function baseFieldDefinitions($entity_type) {
       ->setDescription(t('Whether the user is active (1) or blocked (0).'))
       ->setSetting('default_value', 1);
 
-    // @todo Convert to a "created" field in https://drupal.org/node/2145103.
-    $fields['created'] = FieldDefinition::create('integer')
+    $fields['created'] = FieldDefinition::create('created')
       ->setLabel(t('Created'))
       ->setDescription(t('The time that the user was created.'));
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['access'] = FieldDefinition::create('integer')
+    $fields['access'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Last access'))
       ->setDescription(t('The time that the user last accessed the site.'))
       ->setSetting('default_value', 0);
 
-    // @todo Convert to a "timestamp" field in https://drupal.org/node/2145103.
-    $fields['login'] = FieldDefinition::create('integer')
+    $fields['login'] = FieldDefinition::create('timestamp')
       ->setLabel(t('Last login'))
       ->setDescription(t('The time that the user last logged in.'))
       ->setSetting('default_value', 0);
