diff --git a/auto_entitylabel.module b/auto_entitylabel.module
index 758c220..c043977 100644
--- a/auto_entitylabel.module
+++ b/auto_entitylabel.module
@@ -1,76 +1,140 @@
 <?php
 
-define('AUTO_ENTITYLABEL_DISABLED', 0);
-define('AUTO_ENTITYLABEL_ENABLED', 1);
-define('AUTO_ENTITYLABEL_OPTIONAL', 2);
-define('AUTO_ENTITYLABEL_PLACEHOLDER', '%AutoEntityLabel%');
+/**
+ * @file
+ * Allows hiding of entity label fields and automatic label creation.
+ */
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Config\Entity\ConfigEntityType;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Url;
 
 /**
  * Implements hook_entity_type_alter().
+ *
+ * Adds the Auto Label tab to the entity configuration page.
  */
 function auto_entitylabel_entity_type_alter(array &$entity_types) {
+  $module_handler = \Drupal::moduleHandler();
   /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
   foreach ($entity_types as $entity_type_id => $entity_type) {
-    if (($entity_type->getFormClass('default') || $entity_type->getFormClass('edit')) && $entity_type->hasLinkTemplate('edit-form')) {
-      $entity_type->setLinkTemplate('auto-label', "/auto-label/$entity_type_id/{{$entity_type_id}}");
+    // Support core entity types only. Contrib and custom entity types should
+    // use a hook or service (@todo https://www.drupal.org/node/2829571).
+    $core_entity = FALSE;
+    $module_name = $entity_type->getProvider();
+    if ($module_name != 'core') {
+      // Identify core entity types that are provided by modules.
+      $module = $module_handler->getModule($module_name);
+      if (preg_match('/^core/', $module->getPath())){
+        $core_entity = TRUE;
+      }
+    }
+    else {
+      // Some core entity types are not provided by a module.
+      $core_entity = TRUE;
+    }
+    if ($core_entity && $entity_type instanceof ConfigEntityType && $entity_type->hasLinkTemplate('edit-form')) {
+      $entity_type->setLinkTemplate('auto-label', $entity_type->getLinkTemplate('edit-form') . "/auto-label");
     }
   }
 }
 
-
 /**
  * Implements hook_form_alter().
  */
-function auto_entitylabel_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
-
+function auto_entitylabel_form_alter(&$form, FormStateInterface $form_state) {
   if (isset($form['#entity_builders']) && empty($form['#auto_entitylabel_processed'])) {
-    $info = $form_state->getFormObject()->getEntity();
-    $type = $info->getEntityType()->id();
-    $bundle = $info->getType();
-    // Exit if there is no label field, e.g. users only have a "label callback"
-    $key =  'auto_entitylabel' . '_' . $type . '_type_' . $bundle;
-    $title_widget = &$form['title']['widget'][0];
-    $form['#auto_entitylabel_processed'] = TRUE;
-
-    // @todo: Port this once title module is released out.
-    /**
-    // Integration with the title module.
-    $replacement = FALSE;
+    $decorator = \Drupal::service('auto_entitylabel.entity_decorator');
+    /** @var \Drupal\auto_entitylabel\AutoEntityLabelManager $entity */
+    $entity = $decorator->decorate($form_state->getFormObject()->getEntity());
 
-    if (module_exists('title') && (title_field_replacement_enabled($form['#entity_type'], $form['#bundle'], $title))) {
-      $title = $info['field replacement'][$title]['instance']['field_name'];
-      $replacement = TRUE;
-    }
-     */
-    $auto_entitylabel_config = \Drupal::config('auto_entitylabel.settings');
-    $bundle_config = $auto_entitylabel_config->get($key);
-    if ($bundle_config == AUTO_ENTITYLABEL_ENABLED) {
-      // @todo: Port this once title module is released out.
-      /**
-      if ($replacement && isset($form[$title])) {
-        $form[$title][$form[$title]['#language']][0]['value']['#value'] = AUTO_ENTITYLABEL_PLACEHOLDER;
-        $form[$title][$form[$title]['#language']][0]['value']['#type'] = 'value';
-        $form[$title][$form[$title]['#language']][0]['value']['#required'] = FALSE;
+    if ($entity instanceof ContentEntityInterface) {
+      if ($entity->hasAutoLabel()) {
+        $label = $entity->getLabelName();
+        $widget = &$form[$label]['widget'][0];
+        // Hide the label field. It will be automatically generated in
+        // hook_entity_presave().
+        $widget['value']['#type'] = 'hidden';
+        $widget['value']['#required'] = FALSE;
+        if (empty($widget['value']['#default_value'])) {
+          $widget['value']['#default_value'] = '%AutoEntityLabel%';
+        }
       }
       else {
-       */
-      // We will autogenerate the title later, just hide the title field in the
-      // meanwhile.
-      $title_widget['value']['#default_value'] = AUTO_ENTITYLABEL_PLACEHOLDER;
-      $title_widget['value']['#type'] = 'value';
-      $title_widget['value']['#required'] = FALSE;
-//      }
+        if ($entity->hasOptionalAutoLabel()) {
+          $label = $entity->getLabelName();
+          $widget = &$form[$label]['widget'][0];
+          // Allow label field to be empty. It will be automatically generated
+          // in hook_entity_presave().
+          $widget['value']['#required'] = FALSE;
+        }
+      }
+
+      $form['#auto_entitylabel_processed'] = TRUE;
     }
-    elseif ($bundle_config == AUTO_ENTITYLABEL_OPTIONAL) {
-      // @todo: Port this once title module is released out.
-      /**
-      if ($replacement && isset($form[$title])) {
-        $form[$title][$form[$title]['#language']][0]['value']['#required'] = FALSE;
+  }
+}
+
+/**
+ * Implements hook_entity_prepare_view().
+ */
+function auto_entitylabel_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
+  foreach ($entities as $entity) {
+    if ($entity->in_preview === TRUE && $entity instanceof ContentEntityInterface) {
+      $decorator = \Drupal::service('auto_entitylabel.entity_decorator');
+      /** @var \Drupal\auto_entitylabel\AutoEntityLabelManager $decorated_entity */
+      $decorated_entity = $decorator->decorate($entity);
+
+      if ($decorated_entity->hasLabel() && $decorated_entity->autoLabelNeeded()) {
+        $decorated_entity->setLabel();
       }
-      else {
-       */
-      $title_widget['value']['#required'] = FALSE;
-//      }
     }
   }
 }
+
+/**
+ * Implements hook_entity_presave().
+  */
+function auto_entitylabel_entity_presave(EntityInterface $entity) {
+  if ($entity instanceof ContentEntityInterface) {
+    $decorator = \Drupal::service('auto_entitylabel.entity_decorator');
+    /** @var \Drupal\auto_entitylabel\AutoEntityLabelManager $decorated_entity */
+    $decorated_entity = $decorator->decorate($entity);
+    if ($decorated_entity->hasLabel() && $decorated_entity->autoLabelNeeded()) {
+      $decorated_entity->setLabel();
+    }
+  }
+}
+
+/**
+ * Implements hook_validation_constraint_alter().
+ *
+ * Override core NotNull constraint to allow entities that use Auto Entity
+ * Labels to validate when their label is empty before being set automatically.
+ */
+function auto_entitylabel_validation_constraint_alter(array &$definitions) {
+  $definitions['NotNull']['class'] = 'Drupal\auto_entitylabel\Plugin\Validation\EntityLabelNotNullConstraint';
+}
+
+/**
+ * Implements hook_entity_operation().
+ */
+function auto_entitylabel_entity_operation(EntityInterface $entity) {
+  $operations = array();
+  $entity_type = $entity->getEntityType();
+  $entity_type_id = $entity_type->id();
+  $entity_id = $entity->id();
+  if ($entity->hasLinkTemplate('auto-label') &&
+    \Drupal::currentUser()->hasPermission('administer ' . $entity_type_id . ' labels')) {
+
+    $operations['auto-label'] = array(
+      'title' => t('Manage automatic entity labels'),
+      'weight' => 100,
+      'url' => Url::fromRoute("entity.{$entity_type_id}.auto_label", array($entity_type_id => $entity_id)),
+    );
+  }
+
+  return $operations;
+}
\ No newline at end of file
diff --git a/auto_entitylabel.permissions.yml b/auto_entitylabel.permissions.yml
index b3bb478..e50813f 100644
--- a/auto_entitylabel.permissions.yml
+++ b/auto_entitylabel.permissions.yml
@@ -1,2 +1,2 @@
 permission_callbacks:
-  - Drupal\auto_entitylabel\AutoEntityLabelPermisssionController::autoEntityLabelPermissions
\ No newline at end of file
+  - Drupal\auto_entitylabel\AutoEntityLabelPermissionController::autoEntityLabelPermissions
\ No newline at end of file
diff --git a/auto_entitylabel.services.yml b/auto_entitylabel.services.yml
index ed7a7da..eff9deb 100644
--- a/auto_entitylabel.services.yml
+++ b/auto_entitylabel.services.yml
@@ -10,4 +10,8 @@ services:
     tags:
       - { name: route_enhancer }
   auto_entitylabel.manager:
-    class: Drupal\auto_entitylabel\AutoEntityLabelManager
\ No newline at end of file
+    class: Drupal\auto_entitylabel\AutoEntityLabelManager
+    arguments: ['@entity.manager', '@config.factory', '@entity_type.manager', '@token']
+  auto_entitylabel.entity_decorator:
+    class: Drupal\auto_entitylabel\EntityDecorator
+    arguments: ['@config.factory', '@entity_type.manager', '@token']
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..5eafcee
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,8 @@
+{
+  "name": "drupal/auto_entitylabel",
+  "description": "Allows hiding of entity label fields and automatic label creation.",
+  "type": "drupal-module",
+  "license": "GPL-2.0+",
+  "minimum-stability": "dev",
+  "require": { }
+}
diff --git a/src/AutoEntityLabelManager.php b/src/AutoEntityLabelManager.php
index 5a11c9c..b1af38f 100644
--- a/src/AutoEntityLabelManager.php
+++ b/src/AutoEntityLabelManager.php
@@ -1,23 +1,327 @@
 <?php
+/**
+ * @file
+ * Contains \Drupal\auto_entitylabel\AutoEntityLabelManager.
+ */
+
 namespace Drupal\auto_entitylabel;
 
-class AutoENtityLabelManager {
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Utility\Token;
+
+class AutoEntityLabelManager implements AutoEntityLabelManagerInterface {
+  use StringTranslationTrait;
+
+  /**
+   * Automatic label is disabled.
+   */
+  const DISABLED = 0;
+
+  /**
+   * Automatic label is enabled. Will always be generated.
+   */
+  const ENABLED = 1;
+
+  /**
+   * Automatic label is optional. Will only be generated if no label was given.
+   */
+  const OPTIONAL = 2;
+
+  /**
+   * The content entity.
+   *
+   * @var ContentEntityInterface
+   */
+  protected $entity;
+
+  /**
+   * The type of the entity.
+   *
+   * @var string
+   */
+  protected $entity_type;
+
+  /**
+   * The bundle of the entity.
+   *
+   * @var string
+   */
+  protected $entity_bundle;
+
+  /**
+   * Indicates if the automatic label has been applied.
+   *
+   * @var bool
+   */
+  protected $auto_label_applied = FALSE;
+
+  /**
+   * Config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Token service.
+   *
+   * @var \Drupal\Core\Utility\Token
+   */
+  protected $token;
+
+  /**
+   * Automatic label configuration.
+   *
+   * @var \Drupal\Core\Config\ImmutableConfig
+   */
+  protected $config;
+
+  /**
+   * Constructs an AutoEntityLabelManager object.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity to add the automatic label to.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   Configuration factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   Entity type manager
+   * @param \Drupal\Core\Utility\Token $token
+   *   Token manager.
+   */
+  public function __construct(ContentEntityInterface $entity, ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, Token $token) {
+    $this->entity = $entity;
+    $this->entity_type = $entity->getEntityType()->id();
+    $this->entity_bundle = $entity->bundle();
+    $this->bundle_entity_type = $entity_type_manager->getDefinition($this->entity_type)->getBundleEntityType();
+
+    $this->configFactory = $config_factory;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->token = $token;
+  }
+
+  /**
+   * Checks if the entity has a label.
+   *
+   * @return bool
+   *   True if the entity has a label property.
+   */
+  public function hasLabel() {
+    /** @var \Drupal\Core\Entity\EntityTypeInterface $definition */
+    $definition = $this->entityTypeManager->getDefinition($this->entity->getEntityTypeId());
+    return $definition->hasKey('label');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setLabel() {
+
+    if (!$this->hasLabel()) {
+      throw new \Exception('This entity has no label.');
+    }
+
+    $pattern = $this->getConfig('pattern') ?: '';
+    $pattern = trim($pattern);
+
+    if ($pattern) {
+      $label = $this->generateLabel($pattern, $this->entity);
+    }
+    else {
+      $label = $this->getAlternativeLabel();
+    }
+
+    $label = substr($label, 0, 255);
+    $label_name = $this->getLabelName();
+    $this->entity->$label_name->setValue($label);
+
+    $this->auto_label_applied = TRUE;
+    return $label;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasAutoLabel() {
+    return $this->getConfig('status') == self::ENABLED;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasOptionalAutoLabel() {
+    return $this->getConfig('status') == self::OPTIONAL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function autoLabelNeeded() {
+    $not_applied = empty($this->auto_label_applied);
+    $required = $this->hasAutoLabel();
+    $optional = $this->hasOptionalAutoLabel() && empty($this->entity->label());
+    return $not_applied && ($required || $optional);
+  }
+
+  /**
+   * Gets the field name of the entity label.
+   *
+   * @return string
+   *   The entity label field name. Empty if the entity has no label.
+   */
+  public function getLabelName() {
+    $label_field = '';
+
+    if ($this->hasLabel()) {
+      $definition = $this->entityTypeManager->getDefinition($this->entity->getEntityTypeId());
+      $label_field = $definition->getKey('label');
+    }
+
+    return $label_field;
+  }
+
+  /**
+   * Gets the entity bundle label or the entity label.
+   *
+   * @return string
+   *   The bundle label.
+   */
+  protected function getBundleLabel() {
+    $entity_type = $this->entity->getEntityTypeId();
+    $bundle = $this->entity->bundle();
+
+    // Use the the human readable name of the bundle type. If this entity has no
+    // bundle, we use the name of the content entity type.
+    if ($bundle != $entity_type) {
+      $bundle_entity_type = $this->entityTypeManager
+        ->getDefinition($entity_type)
+        ->getBundleEntityType();
+      $label = $this->entityTypeManager
+        ->getStorage($bundle_entity_type)
+        ->load($bundle)
+        ->label();
+    }
+    else {
+      $label = $this->entityTypeManager
+        ->getDefinition($entity_type)
+        ->getLabel();
+    }
+
+    return $label;
+  }
+
+  /**
+   * Generates the label according to the settings.
+   *
+   * @param string $pattern
+   *   Label pattern. May contain tokens.
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   Content entity.
+   *
+   * @return string
+   *   A label string
+   */
+  protected function generateLabel($pattern, $entity) {
+    $entity_type = $entity->getEntityType()->id();
+    $output = $this->token
+      ->replace($pattern, array($entity_type => $entity), array(
+        'sanitize' => FALSE,
+        'clear' => TRUE
+      ));
+
+    // Evaluate PHP.
+    if ($this->getConfig('php')) {
+      $output = $this->evalTitle($output, $this->entity);
+    }
+    // Strip tags.
+    $output = preg_replace('/[\t\n\r\0\x0B]/', '', strip_tags($output));
+
+    return $output;
+  }
+
+  /**
+   * Returns automatic label configuration of the content entity bundle.
+   *
+   * @param string $value
+   *   The configuration value to get.
+   *
+   * @return \Drupal\Core\Config\ImmutableConfig
+   */
+  protected function getConfig($value) {
+    if (!isset($this->config)) {
+      $this->config = $this->configFactory->get('auto_entitylabel.settings');
+    }
+    $key = $this->bundle_entity_type . '_' . $this->entity_bundle;
+    return $this->config->get($key . '_' . $value);
+  }
+
+  /**
+   * Gets an alternative entity label.
+   *
+   * @return string
+   *   Translated label string.
+   */
+  protected function getAlternativeLabel() {
+    $content_type = $this->getBundleLabel();
+
+    if ($this->entity->id()) {
+      $label = $this->t('@type @id', array(
+        '@type' => $content_type,
+        '@id' => $this->entity->id(),
+      ));
+    }
+    else {
+      $label = $content_type;
+    }
+
+    return $label;
+  }
+
+  /**
+   * Evaluates php code and passes the entity to it.
+   *
+   * @param $code
+   *   PHP code to evaluate.
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   Content entity to pa ss through to the PHP script.
+   *
+   * @return string
+   *   String to use as label.
+   */
+  protected function evalLabel($code, $entity) {
+    ob_start();
+    print eval('?>' . $code);
+    $output = ob_get_contents();
+    ob_end_clean();
+
+    return $output;
+  }
+
   /**
    * Constructs the list of options for the given bundle.
    */
   public static function auto_entitylabel_options($entity_type, $bundle_name) {
     $options = array(
-      AUTO_ENTITYLABEL_DISABLED => t('Disabled'),
+      'auto_entitylabel_disabled' => t('Disabled'),
     );
     if (self::auto_entitylabel_entity_label_visible($entity_type)) {
       $options += array(
-        AUTO_ENTITYLABEL_ENABLED => t('Automatically generate the label and hide the label field'),
-        AUTO_ENTITYLABEL_OPTIONAL => t('Automatically generate the label if the label field is left empty'),
+        'auto_entitylabel_enabled' => t('Automatically generate the label and hide the label field'),
+        'auto_entitylabel_optional' => t('Automatically generate the label if the label field is left empty'),
       );
     }
     else {
       $options += array(
-        AUTO_ENTITYLABEL_ENABLED => t('Automatically generate the label'),
+        'auto_entitylabel_enabled' => t('Automatically generate the label'),
       );
     }
     return $options;
diff --git a/src/AutoEntityLabelManagerInterface.php b/src/AutoEntityLabelManagerInterface.php
new file mode 100644
index 0000000..dffdbcd
--- /dev/null
+++ b/src/AutoEntityLabelManagerInterface.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\auto_entitylabel\AutoEntityLabelManagerInterface.
+ */
+
+namespace Drupal\auto_entitylabel;
+
+/**
+ * Provides an interface for AutoEntityLabelManager.
+ */
+interface AutoEntityLabelManagerInterface {
+
+  /**
+   * Sets the automatically generated entity label.
+   *
+   * @return string
+   *   The applied label. The entity is updated with this label.
+   */
+  public function setLabel();
+
+  /**
+   * Determines if the entity bundle has auto entity label enabled.
+   *
+   * @return bool
+   *   True if the entity bundle has an automatic label.
+   */
+  public function hasAutoLabel();
+
+  /**
+   * Determines if the entity bundle has an optional automatic label.
+   *
+   * Optional means that if the label is empty, it will be automatically
+   * generated.
+   *
+   * @return bool
+   *   True if the entity bundle has an optional automatic label.
+   */
+  public function hasOptionalAutoLabel();
+
+  /**
+   * Returns whether the automatic label has to be set.
+   *
+   * @return bool
+   *   Returns true if the label should be automatically generated.
+   */
+  public function autoLabelNeeded();
+}
diff --git a/src/AutoEntityLabelPermissionController.php b/src/AutoEntityLabelPermissionController.php
new file mode 100644
index 0000000..c0a8635
--- /dev/null
+++ b/src/AutoEntityLabelPermissionController.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\auto_entitylabel\AutoEntityLabelPermissionController.
+ */
+
+namespace Drupal\auto_entitylabel;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\Config\Entity\ConfigEntityType;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides dynamic permissions of the auto_entitylabel module.
+ */
+class AutoEntityLabelPermissionController implements ContainerInjectionInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a new AutoEntityLabelPermissionController instance.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityTypeManagerInterface $entity_manager) {
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('entity.manager'));
+  }
+
+  /**
+   * Returns an array of auto_entitylabel permissions
+   *
+   * @return array
+   */
+  public function autoEntityLabelPermissions() {
+    $permissions = [];
+
+    foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
+      // Create a permission for each entity type to manage the entity
+      // labels.
+      if ($entity_type->hasLinkTemplate('auto-label') && $entity_type->hasKey('label')) {
+        $permissions['administer ' . $entity_type_id . ' labels'] = [
+          'title' => $this->t('%entity_label: Administer automatic entity labels', ['%entity_label' => $entity_type->getLabel()]),
+          'restrict access' => TRUE,
+        ];
+      }
+    }
+    // Create permission to use PHP in entity label patterns.
+    $permissions['use PHP for auto entity labels'] = [
+      'title' => $this->t('Use PHP for automatic entity label patterns'),
+      'restrict access' => TRUE,
+    ];
+    return $permissions;
+  }
+
+}
diff --git a/src/AutoEntityLabelPermisssionController.php b/src/AutoEntityLabelPermisssionController.php
deleted file mode 100644
index 6b926f1..0000000
--- a/src/AutoEntityLabelPermisssionController.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\auto_entitylabel\AutoEntityLabelPermisssionController.
- */
-
-namespace Drupal\auto_entitylabel;
-
-use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides dynamic permissions of the auto_entitylabel module.
- */
-class AutoEntityLabelPermisssionController implements ContainerInjectionInterface {
-
-  use StringTranslationTrait;
-
-  /**
-   * The entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
-   * Constructs a new AutoEntityLabelPermisssionController instance.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   */
-  public function __construct(EntityManagerInterface $entity_manager) {
-    $this->entityManager = $entity_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static($container->get('entity.manager'));
-  }
-
-  /**
-   * Returns an array of auto_entitylabel permissions
-   *
-   * @return array
-   */
-  public function autoEntityLabelPermissions() {
-    $permissions = [];
-
-    foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
-        // Create a permission for each fieldable entity to manage
-        // the entity labels.
-        $permissions['administer ' . $entity_type_id . ' labels'] = [
-          'title' => $this->t('%entity_label: Administer Entity Labels', ['%entity_label' => $entity_type->getLabel()]),
-          'restrict access' => TRUE,
-        ];
-    }
-
-    return $permissions;
-  }
-
-}
\ No newline at end of file
diff --git a/src/EntityDecorator.php b/src/EntityDecorator.php
new file mode 100644
index 0000000..796b57e
--- /dev/null
+++ b/src/EntityDecorator.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\auto_entitylabel\EntityDecorator.
+ */
+
+namespace Drupal\auto_entitylabel;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Utility\Token;
+
+/**
+ * Provides an content entity decorator for automatic label generation.
+ */
+class EntityDecorator implements EntityDecoratorInterface {
+
+  /**
+   * The content entity that is decorated.
+   *
+   * @var ContentEntityInterface
+   */
+  protected $entity;
+
+  /**
+   * Config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Token service.
+   *
+   * @var \Drupal\Core\Utility\Token
+   */
+  protected $token;
+
+  /**
+   * Automatic label configuration for the entity.
+   *
+   * @var array
+   */
+  protected $config;
+
+  /**
+   * Constructs an EntityDecorator object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   Configuration factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   Entity type manager
+   * @param \Drupal\Core\Utility\Token $token
+   *   Token manager.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, Token $token) {
+    $this->configFactory = $config_factory;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->token = $token;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function decorate(ContentEntityInterface $entity) {
+    $this->entity = new AutoEntityLabelManager($entity, $this->configFactory, $this->entityTypeManager, $this->token);
+    return $this->entity;
+  }
+}
diff --git a/src/EntityDecoratorInterface.php b/src/EntityDecoratorInterface.php
new file mode 100644
index 0000000..26a84c4
--- /dev/null
+++ b/src/EntityDecoratorInterface.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\auto_entitylabel\EntityDecoratorInterface.
+ */
+
+namespace Drupal\auto_entitylabel;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+
+/**
+ * Provides an interface for EntityDecorator.
+ */
+interface EntityDecoratorInterface {
+
+  /**
+   * Automatic entity label entity decorator.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *
+   * @return \Drupal\auto_entitylabel\AutoEntityLabelManager|\Drupal\Core\Entity\ContentEntityInterface
+   */
+  public function decorate(ContentEntityInterface $entity);
+}
diff --git a/src/Form/AutoEntityLabelForm.php b/src/Form/AutoEntityLabelForm.php
index 51f7ab8..ec2aced 100644
--- a/src/Form/AutoEntityLabelForm.php
+++ b/src/Form/AutoEntityLabelForm.php
@@ -7,23 +7,22 @@
 
 namespace Drupal\auto_entitylabel\Form;
 
-use Drupal\auto_entitylabel\AutoENtityLabelManager;
+use Drupal\auto_entitylabel\AutoEntityLabelManager;
 use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\views\Plugin\views\argument\StringArgument;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Class AutoEntityLabelForm.
  *
  * @property \Drupal\Core\Config\ConfigFactoryInterface config_factory
- * @property \Drupal\Core\Entity\EntityManagerInterface entity_manager
+ * @property \Drupal\Core\Entity\EntityTypeManagerInterface entity_manager
  * @property  String entity_type_parameter
  * @property  String entity_type_id
- * @property \Drupal\auto_entitylabel\AutoENtityLabelManager auto_entity_label_manager
+ * @property \Drupal\auto_entitylabel\AutoEntityLabelManager auto_entity_label_manager
  * @package Drupal\auto_entitylabel\Controller
  */
 class AutoEntityLabelForm extends ConfigFormBase {
@@ -46,18 +45,19 @@ class AutoEntityLabelForm extends ConfigFormBase {
   /**
    * AutoEntityLabelController constructor.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    */
-  public function __construct(ConfigFactoryInterface $config_factory, EntityManagerInterface $entity_manager, RouteMatchInterface $route_match, AutoENtityLabelManager $auto_entity_label_manager) {
+  public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_manager, RouteMatchInterface $route_match) {
     parent::__construct($config_factory);
     $this->entitymanager = $entity_manager;
     $this->route_match = $route_match;
-    $this->auto_entity_label_manager = $auto_entity_label_manager;
     $route_options = $this->route_match->getRouteObject()->getOptions();
-    $this->entity_type_parameter = array_shift(array_keys($route_options['parameters']));
+    $array_keys = array_keys($route_options['parameters']);
+    $this->entity_type_parameter = array_shift($array_keys);
     $entity_type = $this->route_match->getParameter($this->entity_type_parameter);
     $this->entity_type_id = $entity_type->id();
+    $this->entity_type_provider =  $entity_type->getEntityType()->getProvider();
   }
 
 
@@ -91,8 +91,7 @@ class AutoEntityLabelForm extends ConfigFormBase {
     return new static (
       $container->get('config.factory'),
       $container->get('entity.manager'),
-      $container->get('current_route_match'),
-      $container->get('auto_entitylabel.manager')
+      $container->get('current_route_match')
     );
   }
 
@@ -100,53 +99,64 @@ class AutoEntityLabelForm extends ConfigFormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $entity_type_parameter = $this->entity_type_parameter;
-    $entity_type_id = $this->entity_type_id;
-    $entity_type = str_replace('_type', '', $entity_type_parameter);
-    $key = $entity_type_parameter . '_' . $entity_type_id;
-
+    $key = $this->entity_type_parameter . '_' . $this->entity_type_id;
     $config = $this->config('auto_entitylabel.settings');
+
+    /*
+     * @todo
+     *  Find a generic way of determining if the label is rendered on the
+     *  entity form. If not, don't show 'auto_entitylabel_optional' option.
+     */
+    $options = array(
+      AutoEntityLabelManager::DISABLED => t('Disabled'),
+      AutoEntityLabelManager::ENABLED => t('Automatically generate the label and hide the label field'),
+      AutoEntityLabelManager::OPTIONAL => t('Automatically generate the label if the label field is left empty'),
+    );
+
     $form['auto_entitylabel'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Automatic label generation for @type', array('@type' => $entity_type_id)),
+      '#title' => t('Automatic label generation for @type', array('@type' => $this->entity_type_id)),
       '#weight' => 0,
     );
 
-    $form['auto_entitylabel']['auto_entitylabel_' . $key] = array(
+    $form['auto_entitylabel'][$key . '_status'] = array(
       '#type' => 'radios',
-      '#default_value' => $config->get('auto_entitylabel_' . $key),
-      '#options' => $this->auto_entity_label_manager->auto_entitylabel_options($entity_type_parameter, $entity_type_id),
+      '#default_value' => $config->get($key . '_status'),
+      '#options' => $options,
     );
 
-    $form['auto_entitylabel']['auto_entitylabel_pattern_' . $key] = array(
+    $form['auto_entitylabel'][$key . '_pattern'] = array(
       '#type' => 'textarea',
-      '#title' => t('Pattern for the title'),
-      '#description' => t('Leave blank for using the per default generated title. Otherwise this string will be used as title. Use the syntax [token] if you want to insert a replacement pattern.'),
-      '#default_value' => $config->get('auto_entitylabel_pattern_' . $key, ''),
+      '#title' => t('Pattern for the label'),
+      '#description' => t('Leave blank for using the per default generated label. Otherwise this string will be used as label. Use the syntax [token] if you want to insert a replacement pattern.'),
+      '#default_value' => $config->get($key . '_pattern'),
     );
 
     // Don't allow editing of the pattern if PHP is used, but the users lacks
     // permission for PHP.
-    if ($this->config('auto_entitylabel')->get('auto_entitylabel_php_' . $key) && !\Drupal::currentUser()->hasPermission('use PHP for label patterns')) {
-      $form['auto_entitylabel']['auto_entitylabel_pattern_' . $key]['#disabled'] = TRUE;
-      $form['auto_entitylabel']['auto_entitylabel_pattern_' . $key]['#description'] = t('You are not allow the configure the pattern for the title, as you lack the %permission permission.', array('%permission' => t('Use PHP for title patterns')));
+    if ($config->get($key . '_php') && !\Drupal::currentUser()->hasPermission('use PHP for auto entity labels')) {
+      $form['auto_entitylabel'][$key . '_pattern']['#disabled'] = TRUE;
+      $form['auto_entitylabel'][$key . '_pattern']['#description'] = t('You are not allowed the configure the pattern for the label, because you do not have the %permission permission.', array('%permission' => t('Use PHP for automatic entity label patterns')));
     }
 
     // Display the list of available placeholders if token module is installed.
-    if (\Drupal::moduleHandler()->moduleExists('token')) {
+    $module_handler = \Drupal::moduleHandler();
+    if ($module_handler->moduleExists('token')) {
+      $token_info = $module_handler->invoke($this->entity_type_provider, 'token_info');
+      $token_types = isset($token_info['types']) ? array_keys($token_info['types']) : [];
       $form['auto_entitylabel']['token_help'] = array(
         '#theme' => 'token_tree_link',
-        '#token_types' => array($entity_type),
+        '#token_types' => $token_types,
         '#dialog' => TRUE,
       );
     }
 
-    $form['auto_entitylabel']['auto_entitylabel_php_' . $key] = array(
-      '#access' => \Drupal::currentUser()->hasPermission('use PHP for label patterns'),
+    $form['auto_entitylabel'][$key . '_php'] = array(
+      '#access' => \Drupal::currentUser()->hasPermission('use PHP for auto entity labels'),
       '#type' => 'checkbox',
       '#title' => t('Evaluate PHP in pattern.'),
       '#description' => $this->t('Put PHP code above that returns your string, but make sure you surround code in <code>&lt;?php</code> and <code>?&gt;</code>. Note that <code>$entity</code> and <code>$language</code> are available and can be used by your code.'),
-      '#default_value' => $config->get('auto_entitylabel_php_' . $key),
+      '#default_value' => $config->get($key . '_php'),
     );
 
     return parent::buildForm($form, $form_state);
@@ -157,12 +167,10 @@ class AutoEntityLabelForm extends ConfigFormBase {
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $key = $this->entity_type_parameter . '_' . $this->entity_type_id;
-    $userInputValues = $form_state->getUserInput();
     $config = $this->configFactory->getEditable('auto_entitylabel.settings');
-    $config->set('auto_entitylabel_php_' . $key, $userInputValues['auto_entitylabel_php_' . $key]);
-    $config->set('auto_entitylabel_pattern_' . $key, $userInputValues['auto_entitylabel_pattern_' . $key]);
-    $config->set('auto_entitylabel_' . $key, $userInputValues['auto_entitylabel_' . $key]);
+    foreach ($form_state->getValues() as $key => $value) {
+      $config->set($key, $value);
+    }
     $config->save();
     parent::submitForm($form, $form_state);
   }
diff --git a/src/Plugin/Derivative/AutoEntityLabelConfigTask.php b/src/Plugin/Derivative/AutoEntityLabelConfigTask.php
index f554c87..2f7eb97 100644
--- a/src/Plugin/Derivative/AutoEntityLabelConfigTask.php
+++ b/src/Plugin/Derivative/AutoEntityLabelConfigTask.php
@@ -3,7 +3,7 @@
 namespace Drupal\auto_entitylabel\Plugin\Derivative;
 
 use Drupal\Component\Plugin\Derivative\DeriverBase;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -12,17 +12,17 @@ class AutoEntityLabelConfigTask extends DeriverBase implements ContainerDeriverI
   /**
    * The entity manager
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
   protected $entityManager;
 
   /**
    * Creates an FieldUiLocalTask object.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
    *   The entity manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
+  public function __construct(EntityTypeManagerInterface $entity_manager) {
     $this->entityManager = $entity_manager;
   }
 
@@ -42,13 +42,14 @@ class AutoEntityLabelConfigTask extends DeriverBase implements ContainerDeriverI
     $this->derivatives = array();
 
     foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
-
-      $this->derivatives["$entity_type_id.auto_label_tab"] = array(
-        'route_name' => "entity.{$entity_type_id}.auto_label",
-        'title' => 'Auto Label',
-        'base_route' => "entity.{$entity_type_id}.edit_form",
-        'weight' => 100,
-      );
+      if ($entity_type->hasLinkTemplate('auto-label')) {
+        $this->derivatives["$entity_type_id.auto_label_tab"] = array(
+          'route_name' => "entity.{$entity_type_id}.auto_label",
+          'title' => 'Automatic label',
+          'base_route' => "entity.{$entity_type_id}.edit_form",
+          'weight' => 100,
+        );
+      }
     }
 
     foreach ($this->derivatives as &$entry) {
@@ -56,4 +57,4 @@ class AutoEntityLabelConfigTask extends DeriverBase implements ContainerDeriverI
     }
     return $this->derivatives;
   }
-}
\ No newline at end of file
+}
diff --git a/src/Plugin/Validation/EntityLabelNotNullConstraint.php b/src/Plugin/Validation/EntityLabelNotNullConstraint.php
new file mode 100644
index 0000000..9ef6ff7
--- /dev/null
+++ b/src/Plugin/Validation/EntityLabelNotNullConstraint.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Drupal\auto_entitylabel\Plugin\Validation;
+
+use Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraint;
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Custom override of NotNull constraint to allow empty entity labels to
+ * validate before the automatic label is set.
+ */
+class EntityLabelNotNullConstraint extends NotNullConstraint {}
diff --git a/src/Plugin/Validation/EntityLabelNotNullConstraintValidator.php b/src/Plugin/Validation/EntityLabelNotNullConstraintValidator.php
new file mode 100644
index 0000000..417a11b
--- /dev/null
+++ b/src/Plugin/Validation/EntityLabelNotNullConstraintValidator.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\auto_entitylabel\Plugin\Validation;
+
+use Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraintValidator;
+use Drupal\Core\Field\FieldItemList;
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * EntityLabelNotNull constraint validator.
+ *
+ * Custom override of NotNull constraint to allow empty entity labels to
+ * validate before the automatic label is set.
+ */
+class EntityLabelNotNullConstraintValidator extends NotNullConstraintValidator {
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($value, Constraint $constraint) {
+    $typed_data = $this->getTypedData();
+    if ($typed_data instanceof FieldItemList && $typed_data->isEmpty()) {
+      $entity = $typed_data->getEntity();
+      $decorator = \Drupal::service('auto_entitylabel.entity_decorator');
+      /** @var \Drupal\auto_entitylabel\AutoEntityLabelManager $decorated_entity */
+      $decorated_entity = $decorator->decorate($entity);
+
+      if ($decorated_entity->hasLabel() && $decorated_entity->autoLabelNeeded()) {
+        return;
+      }
+    }
+    parent::validate($value, $constraint);
+  }
+}
diff --git a/src/Routing/RouteEnhancer.php b/src/Routing/RouteEnhancer.php
index e414d65..0a40607 100644
--- a/src/Routing/RouteEnhancer.php
+++ b/src/Routing/RouteEnhancer.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\auto_entitylabel\Routing;
 
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Routing\Enhancer\RouteEnhancerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
@@ -20,17 +20,17 @@ class RouteEnhancer implements RouteEnhancerInterface {
   /**
    * The entity manager.
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
   protected $entityManager;
 
   /**
    * Constructs a RouteEnhancer object.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
    *   The entity manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
+  public function __construct(EntityTypeManagerInterface $entity_manager) {
     $this->entityManager = $entity_manager;
   }
 
diff --git a/src/Routing/RouteSubscriber.php b/src/Routing/RouteSubscriber.php
index c5d2883..3259f77 100644
--- a/src/Routing/RouteSubscriber.php
+++ b/src/Routing/RouteSubscriber.php
@@ -22,7 +22,7 @@ class RouteSubscriber extends RouteSubscriberBase {
   /**
    * The entity type manager
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
   protected $entityTypeManager;
 
@@ -63,7 +63,7 @@ class RouteSubscriber extends RouteSubscriberBase {
       $route
         ->addDefaults([
           '_form' => '\Drupal\auto_entitylabel\Form\AutoEntityLabelForm',
-          '_title' => 'Auto Label',
+          '_title' => 'Automatic entity label',
         ])
         ->addRequirements([
           '_permission' => 'administer ' . $entity_type_id . ' labels',
