diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 9ce46580ce..1b09b39310 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -163,6 +163,8 @@ function content_translation_entity_type_alter(array &$entity_types) {
       }
       $entity_type->set('translation', $translation);
     }
+
+    $entity_type->addConstraint('ContentTranslationSynchronizedFields');
   }
 }
 
diff --git a/core/modules/content_translation/src/ExtendedFieldTranslationSynchronizerInterface.php b/core/modules/content_translation/src/ExtendedFieldTranslationSynchronizerInterface.php
new file mode 100644
index 0000000000..82c3f8e372
--- /dev/null
+++ b/core/modules/content_translation/src/ExtendedFieldTranslationSynchronizerInterface.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\content_translation;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
+
+/**
+ * Extended field translation synchronizer interface.
+ *
+ * @internal
+ */
+interface ExtendedFieldTranslationSynchronizerInterface extends FieldTranslationSynchronizerInterface {
+
+  /**
+   * Returns the original unchanged entity to be used to detect changes.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity being changed.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface
+   *   The unchanged entity.
+   */
+  public function getOriginalEntity(ContentEntityInterface $entity);
+
+  /**
+   * Returns the field synchronization settings for the specified definitions.
+   *
+   * @param FieldDefinitionInterface[] $field_definitions
+   *   An associative array of field definitions keyed by field name.
+   *
+   * @return string[][]
+   *   An associative array of field definition settings keyed by field name.
+   */
+  public function getSynchronizedFieldSettings(array $field_definitions);
+
+}
diff --git a/core/modules/content_translation/src/FieldTranslationSynchronizer.php b/core/modules/content_translation/src/FieldTranslationSynchronizer.php
index 13b805df8a..09b32d8744 100644
--- a/core/modules/content_translation/src/FieldTranslationSynchronizer.php
+++ b/core/modules/content_translation/src/FieldTranslationSynchronizer.php
@@ -5,11 +5,12 @@
 use Drupal\Core\Config\Entity\ThirdPartySettingsInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 
 /**
  * Provides field translation synchronization capabilities.
  */
-class FieldTranslationSynchronizer implements FieldTranslationSynchronizerInterface {
+class FieldTranslationSynchronizer implements ExtendedFieldTranslationSynchronizerInterface {
 
   /**
    * The entity manager to use to load unchanged entities.
@@ -28,6 +29,45 @@ public function __construct(EntityManagerInterface $entityManager) {
     $this->entityManager = $entityManager;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getOriginalEntity(ContentEntityInterface $entity) {
+    // If we are creating a new translation we need to use the source language
+    // as original language, since source values are the only ones available to
+    // compare against.
+    if (!isset($entity->original)) {
+      $storage = $this->entityManager->getStorage($entity->getEntityTypeId());
+      $original = $entity->isDefaultRevision() ? $storage->loadUnchanged($entity->id()) : $storage->loadRevision($entity->getLoadedRevisionId());
+    }
+    else {
+      $original = $entity->original;
+    }
+    return $original;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSynchronizedFieldSettings(array $field_definitions) {
+    $self = $this;
+    $synchronized_fields = array_filter(array_map(
+      function (FieldDefinitionInterface $field_definition) use ($self) {
+        return $self->getFieldSynchronizationSettings($field_definition);
+      },
+      $field_definitions
+    ));
+    return $synchronized_fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getFieldSynchronizationSettings(FieldDefinitionInterface $field_definition) {
+    return $field_definition instanceof ThirdPartySettingsInterface &&  $field_definition->isTranslatable() &&
+    ($translation_sync = $field_definition->getThirdPartySetting('content_translation', 'translation_sync')) ? $translation_sync : NULL;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -43,8 +83,7 @@ public function synchronizeFields(ContentEntityInterface $entity, $sync_langcode
     }
 
     // If the entity language is being changed there is nothing to synchronize.
-    $entity_type = $entity->getEntityTypeId();
-    $entity_unchanged = isset($entity->original) ? $entity->original : $this->entityManager->getStorage($entity_type)->loadUnchanged($entity->id());
+    $entity_unchanged = $this->getOriginalEntity($entity);
     if ($entity->getUntranslated()->language()->getId() != $entity_unchanged->getUntranslated()->language()->getId()) {
       return;
     }
@@ -57,7 +96,7 @@ public function synchronizeFields(ContentEntityInterface $entity, $sync_langcode
 
       // Sync if the field is translatable, not empty, and the synchronization
       // setting is enabled.
-      if ($field_definition instanceof ThirdPartySettingsInterface && $field_definition->isTranslatable() && !$items->isEmpty() && $translation_sync = $field_definition->getThirdPartySetting('content_translation', 'translation_sync')) {
+      if (($translation_sync = $this->getFieldSynchronizationSettings($field_definition)) && !$items->isEmpty()) {
         // Retrieve all the untranslatable column groups and merge them into
         // single list.
         $groups = array_keys(array_diff($translation_sync, array_filter($translation_sync)));
diff --git a/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php
new file mode 100644
index 0000000000..71c01b16ff
--- /dev/null
+++ b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Drupal\content_translation\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Validation constraint for the entity changed timestamp.
+ *
+ * @internal
+ *
+ * @Constraint(
+ *   id = "ContentTranslationSynchronizedFields",
+ *   label = @Translation("Content translation synchronized fields", context = "Validation"),
+ *   type = {"entity"}
+ * )
+ */
+class ContentTranslationSynchronizedFieldsConstraint extends Constraint {
+
+  public $message = 'Non translatable field elements can only be changed when updating the current revision';
+
+}
diff --git a/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraintValidator.php b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraintValidator.php
new file mode 100644
index 0000000000..6c76baf277
--- /dev/null
+++ b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraintValidator.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace Drupal\content_translation\Plugin\Validation\Constraint;
+
+use Drupal\content_translation\ContentTranslationManagerInterface;
+use Drupal\content_translation\FieldTranslationSynchronizerInterface;
+use Drupal\content_translation\ExtendedFieldTranslationSynchronizerInterface;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+
+/**
+ * Checks that synchronized fields are not changed in pending revisions.
+ *
+ * @internal
+ */
+class ContentTranslationSynchronizedFieldsConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
+
+  /**
+   * The content translation manager.
+   *
+   * @var \Drupal\content_translation\ContentTranslationManagerInterface
+   */
+  protected $contentTranslationManager;
+
+  /**
+   * The field translation synchronizer.
+   *
+   * @var \Drupal\content_translation\ExtendedFieldTranslationSynchronizerInterface
+   */
+  protected $synchronizer;
+
+  /**
+   * The field type plugin manager.
+   *
+   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
+   */
+  protected $fieldTypeManager;
+
+  /**
+   * ContentTranslationSynchronizedFieldsConstraintValidator constructor.
+   *
+   * @param \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager
+   *   The content translation manager.
+   * @param \Drupal\content_translation\FieldTranslationSynchronizerInterface $synchronizer
+   *   The field translation synchronizer.
+   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
+   *   The field type plugin manager.
+   */
+  public function __construct(ContentTranslationManagerInterface $content_translation_manager, FieldTranslationSynchronizerInterface $synchronizer, FieldTypePluginManagerInterface $field_type_manager) {
+    $this->contentTranslationManager = $content_translation_manager;
+    $this->synchronizer = $synchronizer;
+    $this->fieldTypeManager = $field_type_manager;
+  }
+
+  /**
+   * [@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('content_translation.manager'),
+      $container->get('content_translation.synchronizer'),
+      $container->get('plugin.manager.field.field_type')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($value, Constraint $constraint) {
+    if (!$this->synchronizer instanceof ExtendedFieldTranslationSynchronizerInterface) {
+      return;
+    }
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = $value;
+    if ($entity->isNew() || $entity->isDefaultRevision() || !$entity->getEntityType()->isRevisionable()) {
+      return;
+    }
+    $entity_type_id = $entity->getEntityTypeId();
+    if (!$this->contentTranslationManager->isEnabled($entity_type_id, $entity->bundle())) {
+      return;
+    }
+    $settings = $this->synchronizer->getSynchronizedFieldSettings($entity->getFieldDefinitions());
+    if (!$settings) {
+      return;
+    }
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $original */
+    $original = $this->synchronizer->getOriginalEntity($entity);
+    if ($this->hasSynchronizedPropertyChanges($entity, $original, $settings)) {
+      $this->context->addViolation($constraint->message);
+    }
+  }
+
+  /**
+   * Checks whether any synchronized property has changes.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity being validated.
+   * @param \Drupal\Core\Entity\ContentEntityInterface $original
+   *   The original unchanged entity.
+   * @param string[][] $settings
+   *   An associative array of field synchronization settings keyed by field
+   *   name.
+   *
+   * @return bool
+   */
+  protected function hasSynchronizedPropertyChanges(ContentEntityInterface $entity, ContentEntityInterface $original, array $settings) {
+    $field_definitions = $entity->getFieldDefinitions();
+
+    foreach ($settings as $field_name => $field_synchronization_settings) {
+      foreach ($field_synchronization_settings as $group => $translatable) {
+        if (!$translatable && isset($field_definitions[$field_name])) {
+          $field_type_definition = $this->fieldTypeManager->getDefinition($field_definitions[$field_name]->getType());
+          foreach ($field_type_definition['column_groups'][$group]['columns'] as $property) {
+            if ($entity->get($field_name)->{$property} != $original->get($field_name)->{$property}) {
+              return TRUE;
+            }
+          }
+        }
+      }
+    }
+
+    return FALSE;
+  }
+
+}
diff --git a/core/modules/content_translation/tests/modules/content_translation_test/content_translation_test.module b/core/modules/content_translation/tests/modules/content_translation_test/content_translation_test.module
index d1f321b59c..887cf45155 100644
--- a/core/modules/content_translation/tests/modules/content_translation_test/content_translation_test.module
+++ b/core/modules/content_translation/tests/modules/content_translation_test/content_translation_test.module
@@ -5,7 +5,10 @@
  * Helper module for the Content Translation tests.
  */
 
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Session\AccountInterface;
 
 /**
  * Implements hook_entity_bundle_info_alter().
@@ -23,6 +26,19 @@ function content_translation_test_entity_bundle_info_alter(&$bundles) {
   }
 }
 
+/**
+ * Implements hook_entity_access().
+ */
+function content_translation_test_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
+  $access = \Drupal::state()->get('content_translation.entity_access.'. $entity->getEntityTypeId());
+  if (!empty($access[$operation])) {
+    return AccessResult::allowed();
+  }
+  else {
+    return AccessResult::neutral();
+  }
+}
+
 /**
  * Implements hook_form_BASE_FORM_ID_alter().
  *
diff --git a/core/modules/content_translation/tests/src/Kernel/ContentTranslationFieldSyncValidationTest.php b/core/modules/content_translation/tests/src/Kernel/ContentTranslationFieldSyncValidationTest.php
new file mode 100644
index 0000000000..ec5a993277
--- /dev/null
+++ b/core/modules/content_translation/tests/src/Kernel/ContentTranslationFieldSyncValidationTest.php
@@ -0,0 +1,208 @@
+<?php
+
+namespace Drupal\Tests\content_translation\Kernel;
+
+use Drupal\entity_test\Entity\EntityTestMulRev;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\file\Entity\File;
+use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\TestFileCreationTrait;
+use Drupal\user\Entity\User;
+
+/**
+ * Tests the field synchronization validation logic.
+ *
+ * @group content_translation
+ *
+ * @coversDefaultClass \Drupal\content_translation\Plugin\Validation\Constraint\ContentTranslationSynchronizedFieldsConstraintValidator
+ */
+class ContentTranslationFieldSyncValidationTest extends EntityKernelTestBase {
+
+  use TestFileCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['file', 'image', 'language', 'content_translation', 'content_translation_test'];
+
+  /**
+   * The synchronized field name.
+   *
+   * @var string
+   */
+  protected $fieldName = 'sync_field';
+
+  /**
+   * The content translation manager.
+   *
+   * @var \Drupal\content_translation\ContentTranslationManagerInterface|\Drupal\content_translation\BundleTranslationSettingsInterface
+   */
+  protected $contentTranslationManager;
+
+  /**
+   * The test entity storage.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $entity_type_id = 'entity_test_mulrev';
+    $this->installEntitySchema($entity_type_id);
+    $this->installEntitySchema('file');
+    $this->installSchema('file', ['file_usage']);
+
+    ConfigurableLanguage::createFromLangcode('it')->save();
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+
+    $this->storage = $this->entityManager->getStorage($entity_type_id);
+
+    /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
+    $field_storage_config = FieldStorageConfig::create([
+      'field_name' => $this->fieldName,
+      'type' => 'image',
+      'entity_type' => $entity_type_id,
+      'cardinality' => 1,
+      'translatable' => 1,
+    ]);
+    $field_storage_config->save();
+
+    $field_config = FieldConfig::create([
+      'entity_type' => $entity_type_id,
+      'field_name' => $this->fieldName,
+      'bundle' => $entity_type_id,
+      'label' => 'Synchronized field',
+      'translatable' => 1,
+    ]);
+    $field_config->save();
+
+    $column_settings = [
+      'alt' => 'alt',
+      'title' => 'title',
+      'file' => 0,
+    ];
+    $field_config->setThirdPartySetting('content_translation', 'translation_sync', $column_settings);
+    $field_config->save();
+
+    $this->entityManager->clearCachedDefinitions();
+
+    $this->contentTranslationManager = $this->container->get('content_translation.manager');
+    $this->contentTranslationManager->setEnabled($entity_type_id, $entity_type_id, TRUE);
+
+    foreach ($this->getTestFiles('image') as $file) {
+      $entity = File::create((array) $file + ['status' => 1]);
+      $entity->save();
+    }
+
+    $this->state->set('content_translation.entity_access.file', ['view' => TRUE]);
+
+    $account = User::create([
+      'name' => $this->randomMachineName(),
+      'status' => 1,
+    ]);
+    $account->save();
+  }
+
+  /**
+   * Checks that pending revision validation works as expected.
+   *
+   * @covers ::__construct
+   * @covers ::create
+   * @covers ::validate
+   * @covers ::hasSynchronizedPropertyChanges
+   */
+  public function testPendingRevisionValidation() {
+    foreach ([TRUE, FALSE] as $untranslatable_field_widget_display) {
+      $this->doTestPendingRevisionValidation($untranslatable_field_widget_display);
+    }
+  }
+
+  /**
+   * Tests a sequence of validate and save operations.
+   *
+   * @param $untranslatable_field_widget_display
+   *   Whether untranslatable field widgets should be displayed or hidden.
+   */
+  protected function doTestPendingRevisionValidation($untranslatable_field_widget_display) {
+    $this->setUntranslatableFieldWidgetsDisplay($untranslatable_field_widget_display);
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = EntityTestMulRev::create([
+      'uid' => 1,
+      'langcode' => 'en',
+      $this->fieldName => [
+        'target_id' => 1,
+        'alt' => 'test',
+        'title' => 'test',
+      ],
+    ]);
+    $violations = $entity->validate();
+    $this->assertEmpty($violations);
+    $entity->save();
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
+    $revision = $this->storage->createRevision($entity, FALSE);
+    $revision->get($this->fieldName)->target_id = 2;
+    $violations = $revision->validate();
+    $this->assertNotEmpty($violations);
+
+    $revision = $this->storage->createRevision($entity->addTranslation('it'), FALSE);
+    $metadata = $this->contentTranslationManager->getTranslationMetadata($revision);
+    $metadata->setSource('en');
+    $revision->get($this->fieldName)->target_id = 2;
+    $violations = $revision->validate();
+    $this->assertNotEmpty($violations);
+    $revision->isDefaultRevision(TRUE);
+    $revision->validate();
+    $violations = $revision->validate();
+    $this->assertEmpty($violations);
+    $revision->save();
+
+    $revision = $this->storage->createRevision($revision->getTranslation('en'), FALSE);
+    $revision->get($this->fieldName)->alt = 'alt 3';
+    $violations = $revision->validate();
+    $this->assertEmpty($violations);
+    $revision->save();
+
+    $revision = $this->storage->createRevision($revision->getTranslation('it'), FALSE);
+    $revision->get($this->fieldName)->alt = 'alt 4';
+    $violations = $revision->validate();
+    $this->assertEmpty($violations);
+    $revision->save();
+
+    $revision = $this->storage->createRevision($revision);
+    $revision->get($this->fieldName)->target_id = 5;
+    $violations = $revision->validate();
+    $this->assertEmpty($violations);
+    $revision->save();
+
+    $revision = $this->storage->createRevision($revision->getTranslation('en'));
+    $revision->get($this->fieldName)->target_id = 6;
+    $violations = $revision->validate();
+    $this->assertEmpty($violations);
+    $revision->save();
+  }
+
+  /**
+   * Sets untranslatable field widgets' display status.
+   *
+   * @param bool $display
+   *   Whether untransltable field widgets should be displayed.
+   */
+  protected function setUntranslatableFieldWidgetsDisplay($display) {
+    $entity_type_id = $this->storage->getEntityTypeId();
+    $settings = ['untranslatable_fields_hide' => !$display];
+    $this->contentTranslationManager->setBundleTranslationSettings($entity_type_id, $entity_type_id, $settings);
+    /** @var \Drupal\Core\Entity\EntityTypeBundleInfo $bundle_info */
+    $bundle_info = $this->container->get('entity_type.bundle.info');
+    $bundle_info->clearCachedBundles();
+  }
+
+}
