diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 40da4b8..66bdf40 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -52,6 +52,13 @@
   protected $values = array();
 
   /**
+   * The list of field names of any fields that have changed.
+   *
+   * @var string[]
+   */
+  protected $changedFields = array();
+
+  /**
    * The array of fields, each being an instance of FieldItemListInterface.
    *
    * @var array
@@ -428,6 +435,23 @@ public function getFields($include_computed = TRUE) {
   /**
    * {@inheritdoc}
    */
+  public function getChangedFields() {
+    return array_filter($this->getFields(), function ($field) {
+      return isset($this->changedFields[$field->getName()]);
+    });
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function resetChangedFieldList() {
+    $this->changedFields = array();
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getIterator() {
     return new \ArrayIterator($this->getFields());
   }
@@ -592,6 +616,50 @@ public function onChange($name) {
         }
         break;
     }
+
+    if (!isset($this->changedFields[$name][$this->activeLangcode])) {
+      // A Translation is marked dirty if the translated value of a translatable
+      // field changed or is new.
+      // @todo This detection of modifications needs to be replaced by FieldItemList::equals() as soon it's available
+      //
+      $value = $this->{$name}->getValue();
+      foreach ($this->get($name) as $key => $field) {
+        $mainPropertyName = $field->mainPropertyName();
+        if (!$mainPropertyName) {
+          // @todo could that happen, that there's no main property?
+          $this->changedFields[$name][$this->activeLangcode] = TRUE;
+          break;
+        }
+        elseif (isset($value[$key][$mainPropertyName]) && (!isset($this->values[$name][$this->activeLangcode][$key][$mainPropertyName])
+            || $value[$key][$mainPropertyName] != $this->values[$name][$this->activeLangcode][$key][$mainPropertyName])
+        ) {
+          $this->changedFields[$name][$this->activeLangcode] = TRUE;
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasChanges() {
+    if ($this->hasChangesAcrossTranslations()) {
+      foreach ($this->changedFields as $langcodes) {
+        if (isset($langcodes[$this->activeLangcode])) {
+          return TRUE;
+        }
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasChangesAcrossTranslations() {
+    return (bool) count($this->changedFields);
   }
 
   /**
@@ -728,6 +796,8 @@ public function addTranslation($langcode, array $values = array()) {
     $values[$this->defaultLangcodeKey] = FALSE;
 
     $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED;
+    // Todo Review
+    $this->changedFields['__dummy'][$langcode] = TRUE;
     $translation = $this->getTranslation($langcode);
     $definitions = $translation->getFieldDefinitions();
 
@@ -752,6 +822,12 @@ public function removeTranslation($langcode) {
         }
       }
       $this->translations[$langcode]['status'] = static::TRANSLATION_REMOVED;
+      foreach (array_keys($this->changedFields) as $name) {
+        unset($this->changedFields[$name][$langcode]);
+        if (empty($this->changedFields[$name])) {
+          unset($this->changedFields[$name]);
+        }
+      }
     }
     else {
       $message = 'The specified translation (@langcode) cannot be removed.';
@@ -1020,4 +1096,12 @@ public static function bundleFieldDefinitions(EntityTypeInterface $entity_type,
     return array();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+    parent::postSave($storage, $update);
+    $this->resetChangedFieldList();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityChangedInterface.php b/core/lib/Drupal/Core/Entity/EntityChangedInterface.php
index f5ee395..f8892e3 100644
--- a/core/lib/Drupal/Core/Entity/EntityChangedInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityChangedInterface.php
@@ -22,11 +22,20 @@
 interface EntityChangedInterface {
 
   /**
-   * Returns the timestamp of the last entity change.
+   * Returns the timestamp of the last entity change of the current
+   * translation.
    *
    * @return int
    *   The timestamp of the last entity save operation.
    */
   public function getChangedTime();
 
+  /**
+   * Returns the timestamp of the last entity change across all translations.
+   *
+   * @return int
+   *   The timestamp of the last entity save operation across all
+   *   translations.
+   */
+  public function getChangedTimeAcrossTranslations();
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityChangedTrait.php b/core/lib/Drupal/Core/Entity/EntityChangedTrait.php
new file mode 100644
index 0000000..a6b76ce
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityChangedTrait.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\EntityChangedTrait.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Provides a trait for accessing changed time.
+ */
+trait EntityChangedTrait {
+
+  /**
+   * Returns the timestamp of the last entity change of the current
+   * translation.
+   *
+   * @return int
+   *   The timestamp of the last entity save operation.
+   */
+  public function getChangedTime() {
+    return $this->get('changed')->value;
+  }
+
+  /**
+   * Returns the timestamp of the last entity change across all translations.
+   *
+   * @return int
+   *   The timestamp of the last entity save operation across all
+   *   translations.
+   */
+  public function getChangedTimeAcrossTranslations() {
+    $changed = $this->getUntranslated()->getChangedTime();
+    foreach ($this->getTranslationLanguages(FALSE) as $language) {
+      $translation_changed = $this->getTranslation($language->getId())->getChangedTime();
+      if ($translation_changed > $changed) {
+        $changed = $translation_changed;
+      }
+    }
+    return $changed;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
index 566f9b2..cb1fa4a 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
@@ -186,6 +186,21 @@ public function set($field_name, $value, $notify = TRUE);
   public function getFields($include_computed = TRUE);
 
   /**
+   * Gets an array of changed field item lists.
+   *
+   * @return \Drupal\Core\Field\FieldItemListInterface[]
+   *   An array of field item lists implementing, keyed by field name.
+   */
+  public function getChangedFields();
+
+  /**
+   * Resets the list an array of changed field names.
+   *
+   * @return $this
+   */
+  public function resetChangedFieldList();
+
+  /**
    * Reacts to changes to a field.
    *
    * Note that this is invoked after any changes have been applied.
@@ -204,6 +219,17 @@ public function getFields($include_computed = TRUE);
   public function onChange($field_name);
 
   /**
+   * Determines if at least one field item (of the current translation) has been
+   * changed.
+   */
+  public function hasChanges();
+
+  /**
+   * Determines if at least one field item has been changed.
+   */
+  public function hasChangesAcrossTranslations();
+
+  /**
    * Validates the currently set values.
    *
    * @return \Symfony\Component\Validator\ConstraintViolationListInterface
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php
index fe81a63..2b9d159 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraintValidator.php
@@ -24,7 +24,7 @@ public function validate($entity, Constraint $constraint) {
       if (!$entity->isNew()) {
         $saved_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
 
-        if ($saved_entity && $saved_entity->getChangedTime() > $entity->getChangedTime()) {
+        if ($saved_entity && $saved_entity->getChangedTimeAcrossTranslations() > $entity->getChangedTime()) {
           $this->context->addViolation($constraint->message);
         }
       }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php
index 81625d4..ddf99db 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldType;
 
+use Drupal\Core\Entity\FieldableEntityInterface;
+
 /**
  * Defines the 'changed' entity field type.
  *
@@ -30,7 +32,35 @@ class ChangedItem extends CreatedItem {
    */
   public function preSave() {
     parent::preSave();
-    $this->value = REQUEST_TIME;
+
+    $entity = $this->getEntity();
+    if ($entity->isNew() || !$this->getFieldDefinition()->isTranslatable()) {
+      $this->value = REQUEST_TIME;
+    }
+    else {
+      $field_name = $this->getFieldDefinition()->getName();
+      $original = clone $entity->original;
+      if ($this->getFieldDefinition()->isTranslatable()) {
+        $original = $original->getTranslation($entity->language()->getId());
+      }
+      // If the timestamp has not been set explicitly auto detect a modification
+      // of the current translation and set the timestamp if needed.
+      // An example of setting the timestamp explicitly is
+      // \Drupal\content_translation\ContentTranslationMetadataWrapperInterface
+      if ($this->value == $original->{$field_name}->value) {
+        if ($entity instanceof FieldableEntityInterface) {
+          if ($entity->hasChanges()) {
+            $this->value = REQUEST_TIME;
+          }
+        }
+        else {
+          // @todo is this field or its code re-usable for something else than
+          // ContentEntities? However the default behavior is to set the current
+          // REQUEST_TIME as value on save.
+          $this->value = REQUEST_TIME;
+        }
+      }
+    }
   }
 
 }
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 046640c..5777a31 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -8,6 +8,7 @@
 namespace Drupal\block_content\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -77,6 +78,8 @@ class BlockContent extends ContentEntityBase implements BlockContentInterface {
    */
   protected $theme;
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -210,13 +213,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getRevisionLog() {
     return $this->get('revision_log')->value;
   }
diff --git a/core/modules/comment/src/CommentInterface.php b/core/modules/comment/src/CommentInterface.php
index c141706..0d558b5 100644
--- a/core/modules/comment/src/CommentInterface.php
+++ b/core/modules/comment/src/CommentInterface.php
@@ -197,14 +197,6 @@ public function getCreatedTime();
   public function setCreatedTime($created);
 
   /**
-   * Returns the timestamp of when the comment was updated.
-   *
-   * @return int
-   *   The timestamp of when the comment was updated.
-   */
-  public function getChangedTime();
-
-  /**
    * Checks if the comment is published.
    *
    * @return bool
diff --git a/core/modules/comment/src/CommentStatistics.php b/core/modules/comment/src/CommentStatistics.php
index 588c831..09575a3 100644
--- a/core/modules/comment/src/CommentStatistics.php
+++ b/core/modules/comment/src/CommentStatistics.php
@@ -127,7 +127,7 @@ public function create(FieldableEntityInterface $entity, $fields) {
       // Default to REQUEST_TIME when entity does not have a changed property.
       $last_comment_timestamp = REQUEST_TIME;
       if ($entity instanceof EntityChangedInterface) {
-        $last_comment_timestamp = $entity->getChangedTime();
+        $last_comment_timestamp = $entity->getChangedTimeAcrossTranslations();
       }
       $query->values(array(
         'entity_id' => $entity->id(),
@@ -243,9 +243,9 @@ public function update(CommentInterface $comment) {
         ->fields(array(
           'cid' => 0,
           'comment_count' => 0,
-          // Use the created date of the entity if it's set, or default to
+          // Use the changed date of the entity if it's set, or default to
           // REQUEST_TIME.
-          'last_comment_timestamp' => ($entity instanceof EntityChangedInterface) ? $entity->getChangedTime() : REQUEST_TIME,
+          'last_comment_timestamp' => ($entity instanceof EntityChangedInterface) ? $entity->getChangedTimeAcrossTranslations() : REQUEST_TIME,
           'last_comment_name' => '',
           'last_comment_uid' => $last_comment_uid,
         ))
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index 798a69f..37be4ff 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Number;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\comment\CommentInterface;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -63,6 +64,8 @@ class Comment extends ContentEntityBase implements CommentInterface {
    */
   protected $threadLock = '';
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -517,13 +520,6 @@ public function setThread($thread) {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public static function preCreate(EntityStorageInterface $storage, array &$values) {
     if (empty($values['comment_type']) && !empty($values['field_name']) && !empty($values['entity_type'])) {
       $field_storage = FieldStorageConfig::loadByName($values['entity_type'], $values['field_name']);
diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php
index 9205de8..c01e32f 100644
--- a/core/modules/comment/src/Form/CommentAdminOverview.php
+++ b/core/modules/comment/src/Form/CommentAdminOverview.php
@@ -213,7 +213,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $type = '
             '#url' => $commented_entity->urlInfo(),
           ),
         ),
-        'changed' => $this->dateFormatter->format($comment->getChangedTime(), 'short'),
+        'changed' => $this->dateFormatter->format($comment->getChangedTimeAcrossTranslations(), 'short'),
       );
       $comment_uri_options = $comment->urlInfo()->getOptions();
       $links = array();
diff --git a/core/modules/comment/src/Tests/CommentTokenReplaceTest.php b/core/modules/comment/src/Tests/CommentTokenReplaceTest.php
index a5eaad8..c45c0f7 100644
--- a/core/modules/comment/src/Tests/CommentTokenReplaceTest.php
+++ b/core/modules/comment/src/Tests/CommentTokenReplaceTest.php
@@ -61,7 +61,7 @@ function testCommentTokenReplacement() {
     $tests['[comment:url]'] = $comment->url('canonical', $url_options + array('fragment' => 'comment-' . $comment->id()));
     $tests['[comment:edit-url]'] = $comment->url('edit-form', $url_options);
     $tests['[comment:created:since]'] = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $comment->getCreatedTime(), 2, $language_interface->getId());
-    $tests['[comment:changed:since]'] = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $comment->getChangedTime(), 2, $language_interface->getId());
+    $tests['[comment:changed:since]'] = \Drupal::service('date.formatter')->formatInterval(REQUEST_TIME - $comment->getChangedTimeAcrossTranslations(), 2, $language_interface->getId());
     $tests['[comment:parent:cid]'] = $comment->hasParentComment() ? $comment->getParentComment()->id() : NULL;
     $tests['[comment:parent:title]'] = SafeMarkup::checkPlain($parent_comment->getSubject());
     $tests['[comment:entity]'] = SafeMarkup::checkPlain($node->getTitle());
diff --git a/core/modules/content_translation/src/ContentTranslationMetadataWrapperInterface.php b/core/modules/content_translation/src/ContentTranslationMetadataWrapperInterface.php
index 4a0a65b..cfc8622 100644
--- a/core/modules/content_translation/src/ContentTranslationMetadataWrapperInterface.php
+++ b/core/modules/content_translation/src/ContentTranslationMetadataWrapperInterface.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\content_translation;
 
-use Drupal\Core\Entity\EntityChangedInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\user\UserInterface;
 
 /**
@@ -17,7 +15,7 @@
  * This acts as a wrapper for an entity translation object, encapsulating the
  * logic needed to retrieve translation metadata.
  */
-interface ContentTranslationMetadataWrapperInterface extends EntityChangedInterface {
+interface ContentTranslationMetadataWrapperInterface {
 
   /**
    * Retrieves the source language for this translation.
@@ -110,6 +108,15 @@ public function getCreatedTime();
   public function setCreatedTime($timestamp);
 
   /**
+   * Returns the timestamp of the last entity change of the current
+   * translation.
+   *
+   * @return int
+   *   The timestamp of the last entity save operation.
+   */
+  public function getChangedTime();
+
+  /**
    * Sets the translation modification timestamp.
    *
    * @param int $timestamp
diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index 42de0ae..e30aeb8 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -8,10 +8,10 @@
 namespace Drupal\file\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\Language\LanguageInterface;
 use Drupal\file\FileInterface;
 use Drupal\user\UserInterface;
 
@@ -38,6 +38,8 @@
  */
 class File extends ContentEntityBase implements FileInterface {
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -111,13 +113,6 @@ public function getCreatedTime() {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getOwner() {
     return $this->get('uid')->entity;
   }
diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
index 5570a2a..1d50dc2 100644
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -8,6 +8,7 @@
 namespace Drupal\menu_link_content\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -59,6 +60,8 @@ class MenuLinkContent extends ContentEntityBase implements MenuLinkContentInterf
    */
   protected $insidePlugin = FALSE;
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -132,13 +135,6 @@ public function getWeight() {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getPluginDefinition() {
     $definition = array();
     $definition['class'] = 'Drupal\menu_link_content\Plugin\Menu\MenuLinkContent';
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 4550a6d..d7e4d68 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -751,8 +751,9 @@ function node_page_title(NodeInterface $node) {
  *       for validation, which will be done by EntityChangedConstraintValidator.
  */
 function node_last_changed($nid, $langcode = NULL) {
-  $changed = \Drupal::entityManager()->getStorage('node')->loadUnchanged($nid)->getChangedTime();
-  return $changed ? $changed : FALSE;
+  $node = \Drupal::entityManager()->getStorage('node')->loadUnchanged($nid);
+  $changed = $langcode ? $node->getTranslation($langcode)->getChangedTime() : $node->getChangedTimeAcrossTranslations();
+  return $changed ?: FALSE;
 }
 
 /**
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 7ae8f36..775fd49 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -69,6 +70,8 @@
  */
 class Node extends ContentEntityBase implements NodeInterface {
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -218,13 +221,6 @@ public function setCreatedTime($timestamp) {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function isPromoted() {
     return (bool) $this->get('promote')->value;
   }
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 44fccbf..d88393d 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -289,7 +289,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
   public function validate(array $form, FormStateInterface $form_state) {
     $node = parent::validate($form, $form_state);
 
-    if ($node->id() && (node_last_changed($node->id(), $this->getFormLangcode($form_state)) > $node->getChangedTime())) {
+    if ($node->id() && (node_last_changed($node->id()) > $node->getChangedTimeAcrossTranslations())) {
       $form_state->setErrorByName('changed', $this->t('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.'));
     }
 
diff --git a/core/modules/node/src/Tests/NodeLastChangedTest.php b/core/modules/node/src/Tests/NodeLastChangedTest.php
index 4444cc1..23fa4b4 100644
--- a/core/modules/node/src/Tests/NodeLastChangedTest.php
+++ b/core/modules/node/src/Tests/NodeLastChangedTest.php
@@ -38,7 +38,7 @@ function testNodeLastChanged() {
 
     // Test node last changed timestamp.
     $changed_timestamp = node_last_changed($node->id());
-    $this->assertEqual($changed_timestamp, $node->getChangedTime(), 'Expected last changed timestamp returned.');
+    $this->assertEqual($changed_timestamp, $node->getChangedTimeAcrossTranslations(), 'Expected last changed timestamp returned.');
 
     $changed_timestamp = node_last_changed($node->id(), $node->language()->getId());
     $this->assertEqual($changed_timestamp, $node->getChangedTime(), 'Expected last changed timestamp returned.');
diff --git a/core/modules/node/src/Tests/NodeSaveTest.php b/core/modules/node/src/Tests/NodeSaveTest.php
index c9dc9c0..d1dafb5 100644
--- a/core/modules/node/src/Tests/NodeSaveTest.php
+++ b/core/modules/node/src/Tests/NodeSaveTest.php
@@ -130,7 +130,10 @@ function testTimestamps() {
     $node->save();
     $node = $this->drupalGetNodeByTitle($edit['title'], TRUE);
     $this->assertEqual($node->getCreatedTime(), 979534800, 'Updating a node uses user-set "created" timestamp.');
-    $this->assertNotEqual($node->getChangedTime(), 280299600, 'Updating a node does not use user-set "changed" timestamp.');
+    // Allowing setting changed timestamps is required see
+    // Drupal\content_translation\ContentTranslationMetadataWrapper::setChangedTime($timestamp)
+    // for example
+    $this->assertEqual($node->getChangedTime(), 280299600, 'Updating a node uses user-set "changed" timestamp.');
   }
 
   /**
diff --git a/core/modules/node/src/Tests/NodeTranslationChangedTest.php b/core/modules/node/src/Tests/NodeTranslationChangedTest.php
new file mode 100644
index 0000000..25b814f
--- /dev/null
+++ b/core/modules/node/src/Tests/NodeTranslationChangedTest.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node\Tests\NodeTranslationChangedTest.
+ */
+
+namespace Drupal\node\Tests;
+
+/**
+ * Tests Node Translation specific Changed Timestamps.
+ *
+ * @group node
+ */
+class NodeTranslationChangedTest extends NodeTranslationUITest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function run(array $methods = array()) {
+    if (empty($methods)) {
+      $class = get_class($this);
+      // Iterate through all the methods in this class,
+      // unless a specific list of methods to run was passed.
+      $methods = array_filter(get_class_methods($class), function ($method) {
+        return (strpos($method, 'test') === 0) && (!in_array($method, array(
+          // Avoid to run these tests implemented in NodeTranslationUITest
+          // twice.
+          'testTranslationUI',
+          'testTranslationLinkTheme',
+          'testDisabledBundle',
+          'testTranslationRendering',
+        )));
+      });
+    }
+    parent::run($methods);
+  }
+
+  /**
+   * Tests the translation specific revisions.
+   */
+  public function testTranslationRevisions() {
+    $this->doTestBasicTranslation();
+    $this->doTestTranslationChanged();
+  }
+
+  /**
+   * Tests the basic translation workflow.
+   */
+  protected function doTestTranslationChanged() {
+    $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+    for ($i = 1; $i <= 2; $i++) {
+      foreach ($entity->getTranslationLanguages() as $language) {
+        // Ensure different timestamps.
+        sleep(2);
+
+        $langcode = $language->getId();
+        $counters[$langcode] = $i;
+
+        // Set the title and the custom translatable field and the revision log
+        // to predictable values containing a counter.
+        $edit = array(
+          'title[0][value]' => 'title ' . $langcode . ' ' . $i,
+          $this->fieldName . '[0][value]' => $this->fieldName . ' ' . $langcode . ' ' . $i,
+        );
+        $edit_path = $entity->urlInfo('edit-form', array('language' => $language));
+        $this->drupalPostForm($edit_path, $edit, $this->getFormSubmitAction($entity, $langcode));
+
+        $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+        $this->assertEqual(
+          $entity->getChangedTimeAcrossTranslations(), $entity->getTranslation($langcode)->getChangedTime(),
+          format_string('Changed time for language %language is the latest change over all languages.', array('%language' => $language->getName()))
+        );
+
+        if ($i > 1) {
+          // Because the base class of this test created the translations
+          // without a sleep command, the changed timestamps might not differ
+          // until the second run of that loop.
+          $timestamps = array();
+          foreach ($entity->getTranslationLanguages() as $language) {
+            $next_timestamp = $entity->getTranslation($language->getId())
+              ->getChangedTime();
+            if (!in_array($next_timestamp, $timestamps)) {
+              $timestamps[] = $next_timestamp;
+            }
+          }
+          $this->assertTrue(
+            count($timestamps) == count($entity->getTranslationLanguages()),
+            'All timestamps from all languages are different.'
+          );
+        }
+      }
+    }
+  }
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
index 9f92e7a..60fea13 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -32,6 +33,8 @@
  */
 class EntityTestConstraints extends EntityTest implements EntityChangedInterface {
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -44,11 +47,4 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     return $fields;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
 }
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 7ca9dd7..c620a79 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -56,6 +57,8 @@
  */
 class Term extends ContentEntityBase implements TermInterface {
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -186,13 +189,6 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getDescription() {
     return $this->get('description')->value;
   }
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 1a78c98..3be57a8 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -76,6 +77,8 @@ class User extends ContentEntityBase implements UserInterface {
    */
   protected $hostname;
 
+  use EntityChangedTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -413,13 +416,6 @@ public function setUsername($username) {
   /**
    * {@inheritdoc}
    */
-  public function getChangedTime() {
-    return $this->get('changed')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function setExistingPassword($password) {
     $this->get('pass')->existing = $password;
   }
