Why does deleting a translation on my custom entity delete the entire record? I have defined a custom content entity. (You may find the details below.) If I create an entry in the table and a translation for the entry and then delete the translation it removes the entire entry.

/**
 * @ContentEntityType(
 *   id = "my_custom_entity",
 *   label = @Translation("My Custom Entity"),
 *   handlers = {
 *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
 *     "access" = "Drupal\my_custom_entity\MyCustomEntityAccessControlHandler",
 *     "form" = {
 *       "default" = "Drupal\my_custom_entity\Form\MyCustomEntityForm",
 *       "delete" = "Drupal\my_custom_entity\Form\MyCustomEntityDeleteForm",
 *     },
 *     "list_builder" = "Drupal\my_custom_entity\Entity\Controller\MyCustomEntityListBuilder",
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "views_data" = "Drupal\my_custom_entity\MyCustomEntityViewsData",
 *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
 *   },
 *   translatable = TRUE,
 *   base_table = "my_custom_entity",
 *   data_table = "my_custom_entity_field_data",
 *   fieldable = FALSE,
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "label",
 *     "langcode" = "langcode"
 *   },
 *   links = {
 *     "canonical" = "/my_custom_entity/{my_custom_entity}",
 *     "edit-form" = "/my_custom_entity/{my_custom_entity}/edit",
 *     "delete-form" = "/my_custom_entity/{my_custom_entity}/delete",
 *     "collection" = "/my_custom_entity/list"
 *   },
 *   list_cache_contexts = {"user"}
 * )
 */


Update: I've made a bit of progress on this. The issue seems to be that the entity provides a delete-form. On account of this core/modules/content_translation/src/Access/ContentTranslationManageAccessCheck::access ends up returning AccessResult::forbidden() on line 85 (Drupal 8.3.7) when looking at the path /my_custom_entity/{my_custom_entity}/translations/delete/{language}. Instead it uses /my_custom_entity/{my_custom_entity}/delete. Now I've got to figure out what I'm supposed to do instead. The User entity does not declare a delete-form, but the Node entity does. My initial attempt at removing the delete-form key on my entity resulted in Uncaught PHP Exception Symfony\\Component\\Routing\\Exception\\RouteNotFoundException: "Route "entity.my_custom_entity.delete_form" does not exist." at /var/www/html/drupal8/core/lib/Drupal/Core/Routing/RouteProvider.php line 190. However, I didn't actually uninstall and reinstall the module. I just visited the Extend page and cleared cache.
TL;DR: Extend ContentEntityDeleteForm instead of ContentEntityConfirmFormBase.

The solution was to pattern my approach after the way Node and Taxonomy Terms create their delete forms. I changed my delete form to extend ContentEntityDeleteForm instead of extending ContentEntityConfirmFormBase. Look at ContentEntityDeleteForm::submitForm

// Make sure that deleting a translation does not delete the whole entity.
if (!$entity-&gt;isDefaultTranslation()) {
  $untranslated_entity = $entity-&gt;getUntranslated();
  $untranslated_entity-&gt;removeTranslation($entity-&gt;language()-&gt;getId());
  $untranslated_entity-&gt;save();
  $form_state-&gt;setRedirectUrl($untranslated_entity-&gt;urlInfo('canonical'));
}
else {
  $entity-&gt;delete();
  $form_state-&gt;setRedirectUrl($this-&gt;getRedirectUrl());
}


It explicitly takes care not to delete the whole entity when you are deleting a translation.

ContentEntityConfirmFormBase inherits the ContentEntityForm::submitForm method, which in turn executes the EntityForm::submitForm method. The entity never gets deleted anywhere in that process. Thus, I needed to override the submitForm method in my class. I hadn't included the necessary logic to account for translations, though. Rather than reproducing the necessary logic in an overridden submitForm method, it made more sense to change the class that I was extending.