--- a/src/Normalizer/ContentEntityNormalizer.php
+++ b/src/Normalizer/ContentEntityNormalizer.php
@@ -292,7 +292,7 @@ class ContentEntityNormalizer implements NormalizerInterface, DenormalizerInterf
         // \Drupal\Core\TypedData\DataDefinition::isReadOnly() checks if it is
         // computed so we can't rely on it. Get the definition array instead.
         $definition_array = $definition->toArray();
-        if (!empty($definition_array['internal']) || !empty($definition_array['read-only'])) {
+        if (!empty($definition_array['internal'])) {
           return FALSE;
         }
       }
@@ -302,6 +302,12 @@ class ContentEntityNormalizer implements NormalizerInterface, DenormalizerInterf
     // Ignore langcode and default_langcode.
     /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
     $entity_type = $entity->getEntityType();
+    // Ignore entity keys (id, uuid, bundle, revision) - they are in _meta.
+    foreach (['id', 'uuid', 'bundle', 'revision'] as $key) {
+      if ($entity_key = $entity_type->getKey($key)) {
+        unset($fields[$entity_key]);
+      }
+    }
     if ($langcode_key = $entity_type->getKey('langcode')) {
       unset($fields[$langcode_key]);
       unset($fields[$entity_type->getKey('default_langcode')]);
