diff --git a/conditional_fields.api.php b/conditional_fields.api.php
new file mode 100644
index 0000000..efa4c26
--- /dev/null
+++ b/conditional_fields.api.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Hooks for the conditional_fields module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Build a list of available fields.
+ *
+ * Fields that use the Field API should be available to Confitional Fields
+ * automatically. This hook provides a mechanism to register pseudo-fields
+ * (such as those provided by Field Group.)
+ *
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ *
+ * @return array Fields provided by this module.
+ *   Keyed by machine name, with field labels as values.
+ *
+ * @see ConditionalFieldForm::getFields().
+ * @see hook_conditional_fields_alter().
+ * @see conditional_fields_conditional_fields().
+ */
+function hook_conditional_fields($entity_type, $bundle_name) {
+  $fields = [];
+  $groups = field_group_info_groups($entity_type, $bundle_name, 'form', 'default');
+  foreach ($groups as $name => $group) {
+    $fields[$name] = $group->label;
+  }
+  return $fields;
+}
+
+/**
+ * Alter the list of available fields.
+ *
+ * @param string &$fields
+ *   Fields provided by hook_conditional_fields().
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ * @param string $fields
+ *   Fields available to this module, provided by modules that implement
+ *   hook_conditional_fields().
+ *
+ * @see ConditionalFieldForm::getFields().
+ * @see hook_conditional_fields().
+ * @see conditional_fields_conditional_fields_alter().
+ */
+function hook_conditional_fields_alter(&$fields, $entity_type, $bundle_name) {
+  asort($fields);
+}
+
+/**
+ * Return a list of fields contained within a given field.
+ *
+ * Various modules provide fields that themselves contain other fields (e.g.,
+ * Field Group, Paragraphs, etc.) This hook allows those modules to provide the
+ * logic necessary to determine which fields are contained within such a field.
+ *
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ * @param string $field
+ *   Name of the parent field to check for children fields.
+ *
+ * @return array List of field names.
+ *
+ * @see DependencyHelper::getInheritingFieldNames().
+ * @see hook_conditional_fields_children_alter().
+ * @see field_group_conditional_fields_children().
+ */
+function hook_conditional_fields_children($entity_type, $bundle_name, $field) {
+  $groups = field_group_info_groups($entity_type, $bundle_name, 'form', 'default');
+  return $groups[$field]['children'];
+}
+
+/**
+ * Alter the list of fields contained within a given field.
+ *
+ * @param string &$fields
+ *   Fields provided by hook_conditional_fields_children().
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ * @param string $field
+ *   Name of the parent field to check for children fields.
+ *
+ * @see DependencyHelper::getInheritingFieldNames().
+ * @see hook_conditional_fields_children().
+ */
+function hook_conditional_fields_children_alter(&$fields, $entity_type, $bundle_name, $field) {
+  // Do something with the children fields.
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/conditional_fields.module b/conditional_fields.module
index f3bb665..95fd6d4 100644
--- a/conditional_fields.module
+++ b/conditional_fields.module
@@ -12,6 +12,7 @@ use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\WidgetInterface;
 use Drupal\Core\Url;
 use Drupal\conditional_fields\ConditionalFieldsFormHelper;
+use Drupal\conditional_fields\DependencyHelper;
 
 /**
  * Dependency is triggered if the dependee has a certain value.
@@ -147,6 +148,28 @@ function conditional_fields_element_info_alter(array &$types) {
   }
 }
 
+/**
+ * Implements hook_conditional_fields().
+ *
+ * We implement this on behalf of the core Field module.
+ */
+function conditional_fields_conditional_fields($entity_type, $bundle_name) {
+  $fields = [];
+  $instances = \Drupal::getContainer()->get("entity_field.manager")
+    ->getFieldDefinitions($entity_type, $bundle_name);
+  foreach ($instances as $field) {
+    $fields[$field->getName()] = $field->getLabel();
+  }
+  return $fields;
+}
+
+/**
+ * Implements hook_conditional_fields_alter().
+ */
+function conditional_fields_conditional_fields_alter(&$fields, $entity_type, $bundle_name) {
+  asort($fields);
+}
+
 /**
  * Processes form elements with dependencies.
  *
@@ -206,7 +229,7 @@ function conditional_fields_element_after_build($element, FormStateInterface &$f
       if (isset($dependencies['dependents'][$field_name])) {
         foreach ($dependencies['dependents'][$field_name] as $id => $dependency) {
           if (!isset($form['#conditional_fields'][$field_name]['dependees'][$id]) || conditional_fields_is_priority_field($field)) {
-            conditional_fields_attach_dependency($form, ['#field_name' => $dependency['dependee']], $field, $dependency['options'], $id);
+            conditional_fields_attach_dependency($form, $form_state, ['#field_name' => $dependency['dependee']], $field, $dependency['options'], $id);
           }
         }
       }
@@ -214,7 +237,7 @@ function conditional_fields_element_after_build($element, FormStateInterface &$f
       if (isset($dependencies['dependees'][$field_name])) {
         foreach ($dependencies['dependees'][$field_name] as $id => $dependency) {
           if (!isset($form['#conditional_fields'][$field_name]['dependents'][$id]) || conditional_fields_is_priority_field($field)) {
-            conditional_fields_attach_dependency($form, $field, ['#field_name' => $dependency['dependent']], $dependency['options'], $id);
+            conditional_fields_attach_dependency($form, $form_state, $field, ['#field_name' => $dependency['dependent']], $dependency['options'], $id);
           }
         }
       }
@@ -230,51 +253,12 @@ function conditional_fields_element_after_build($element, FormStateInterface &$f
  * The result can be filtered by providing an entity type and a bundle name.
  */
 function conditional_fields_load_dependencies($entity_type, $bundle) {
-  // Use the advanced drupal_static() pattern.
-  static $dependencies;
-
-  if (!isset($dependencies[$entity_type][$bundle])) {
-    if (!empty($entity_type) && !empty($bundle)) {
-      $dependencies[$entity_type][$bundle] = [];
-    }
-
-    /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity */
-    $entity = \Drupal::entityTypeManager()
-      ->getStorage('entity_form_display')
-      ->load($entity_type . '.' . $bundle . '.default');
-
-    if (!$entity) {
-      return $dependencies;
-    }
-
-    $fields = $entity->getComponents();
-    foreach ($fields as $field_name => $field) {
-      if (empty($field['third_party_settings']['conditional_fields'])) {
-        continue;
-      }
-      foreach ($field['third_party_settings']['conditional_fields'] as $uuid => $conditional_field) {
-        $dependencies[$entity_type][$bundle]['dependents'][$field_name][$uuid] = [
-          'dependee' => $conditional_field['dependee'],
-          'options' => $conditional_field['settings'],
-        ];
-
-        $dependencies[$entity_type][$bundle]['dependees'][$conditional_field['dependee']][$uuid] = [
-          'dependent' => $field_name,
-          'options' => $conditional_field['settings'],
-        ];
-      }
-    }
-  }
-
-  if ($entity_type && isset($dependencies[$entity_type])) {
-    if ($bundle && isset($dependencies[$entity_type][$bundle])) {
-      return $dependencies[$entity_type][$bundle];
-    }
-
-    return $dependencies[$entity_type];
+  static $dependency_helper;
+  if (!isset($dependency_helper)) {
+    $dependency_helper = new DependencyHelper();
   }
 
-  return $dependencies;
+  return $dependency_helper->getDependencies($entity_type, $bundle);
 }
 
 /**
@@ -331,7 +315,7 @@ function conditional_fields_load_dependencies($entity_type, $bundle) {
  *   Note that you don't need to manually set all these options, since default
  *   settings are always provided.
  */
-function conditional_fields_attach_dependency(&$form, $dependee, $dependent, $options, $id = 0) {
+function conditional_fields_attach_dependency(&$form, &$form_state, $dependee, $dependent, $options, $id = 0) {
   module_load_include('inc', 'conditional_fields', 'conditional_fields.api');
   // The absence of the $id parameter identifies a custom dependency.
   if (!$id) {
@@ -386,7 +370,8 @@ function conditional_fields_attach_dependency(&$form, $dependee, $dependent, $op
   // Actual processing is done in
   // \Drupal\conditional_fields\ConditionalFieldsFormHelper::afterBuild().
   // Append the property so the callback runs last.
-  ConditionalFieldsFormHelper::elementAddProperty($form, '#after_build', [ConditionalFieldsFormHelper::class, 'afterBuild'], 'append');
+  $helper = new ConditionalFieldsFormHelper();
+  $helper->elementAddProperty($form, '#after_build', [$helper, 'afterBuild'], 'append');
 }
 
 /**
diff --git a/config/schema/conditional_fields.schema.yml b/config/schema/conditional_fields.schema.yml
index 1832878..c1caa23 100644
--- a/config/schema/conditional_fields.schema.yml
+++ b/config/schema/conditional_fields.schema.yml
@@ -56,3 +56,10 @@ conditional_fields.settings:
     selector:
       type: string
       label: 'Custom jQuery selector'
+    inheritance:
+      type: mapping
+      label: 'Inheritance'
+      mapping:
+        propagate:
+          type: string
+          label: 'Propagate settings to fields contained within this one.'
diff --git a/src/ConditionalFieldsFormHelper.php b/src/ConditionalFieldsFormHelper.php
index 391f0c4..793510c 100644
--- a/src/ConditionalFieldsFormHelper.php
+++ b/src/ConditionalFieldsFormHelper.php
@@ -14,6 +14,14 @@ use Drupal\field\Entity\FieldStorageConfig;
  */
 class ConditionalFieldsFormHelper {
 
+  protected $form;
+  protected $form_state;
+  protected $effects;
+  protected $dependent_location;
+  protected $dependent_form_field;
+  /*  List of all form states. */
+  protected $states;
+
   /**
    * An after_build callback for forms with dependencies.
    *
@@ -21,139 +29,143 @@ class ConditionalFieldsFormHelper {
    * visual effects handling to the States API and attaches a validation callback
    * to the form that handles validation of dependent fields.
    */
-  public static function afterBuild($form, FormStateInterface &$form_state) {
-    // Dependencies data is attached in conditional_fields_element_after_build().
-    if (empty($form['#conditional_fields'])) {
-      return $form;
-    }
-    $form_obj = $form_state->getFormObject();
-    if (!method_exists($form_obj, 'getFormDisplay')) {
-      return $form;
+  public function afterBuild($form, FormStateInterface &$form_state) {
+    $this->form = $form;
+    $this->form_state = $form_state;
+
+    if (!$this->hasConditionalFields()) {
+      return $this->form;
     }
-    // @var EntityFormDisplayInterface $form_display
-    $form_display = $form_obj->getFormDisplay($form_state);
-    $effects = [];
+
+    $this->processDependentFields();
+    $this->addJavascriptEffects();
+    $this->addValidationCallback();
+
+    return $this->form;
+  }
+
+  /**
+   * Build and attach #states properties to dependent fields.
+   */
+  protected function processDependentFields() {
+    $this->effects = [];
 
     // Cycle all dependents.
-    foreach ($form['#conditional_fields'] as $dependent => $dependent_info) {
-      $states = [];
+    foreach ($this->form['#conditional_fields'] as $dependent => $dependent_info) {
+      $this->states = [];
 
-      if (empty($dependent_info['dependees'])) {
+      if (!isset($dependent_info['dependees']) || empty($dependent_info['dependees'])) {
         continue;
       }
+      $dependees = $dependent_info['dependees'];
 
-      $dependent_location = array_merge([], [$dependent]);
-      $dependent_form_field = NestedArray::getValue($form, $dependent_location);
-
-      // Cycle the dependant's dependees.
-      foreach ($dependent_info['dependees'] as $dependency) {
-        $dependee = $dependency['dependee'];
+      $this->dependent_location = array_merge([], [$dependent]);
+      $this->dependent_form_field = NestedArray::getValue($this->form, $this->dependent_location);
 
-        if (empty($form['#conditional_fields'][$dependee])) {
-          continue;
-        }
+      $this->processDependeeFields($dependees);
 
-        $dependee_info = $form['#conditional_fields'][$dependee];
+      if (empty($this->states)) {
+        continue;
+      }
 
-        end($dependee_info['parents']);
-        $unset = key($dependee_info['parents']);
-        if (is_int($dependee_info['parents'][$unset]) && $dependee_info['parents'][$unset] > 0) {
-          unset($dependee_info['parents'][$unset]);
-        }
+      // Save the modified field back into the form.
+      NestedArray::setValue($this->form, $this->dependent_location, $this->dependent_form_field);
 
-        $dependee_form_field = NestedArray::getValue($form, $dependee_info['parents']);
-        $options = $dependency['options'];
+      // Add the #states property to the dependent field.
+      NestedArray::setValue($this->form, array_merge($this->dependent_location, ['#states']), $this->mapStates());
+    }
 
-        if (!empty($options['values']) && is_string($options['values'])) {
-          $options['values'] = explode("\r\n", $options['values']);
-        }
+  }
 
-        $options['selector'] = self::getSelector($options['selector'], $dependee_form_field);
+  /**
+   * Determine and register dependee field effects.
+   */
+  protected function processDependeeFields($dependees) {
+    // Cycle the dependant's dependees.
+    foreach ($dependees as $dependency) {
+      $dependee = $dependency['dependee'];
 
-        $state = self::getState($form_display, $dependee, $dependee_form_field, $options, $form_state);
+      if (empty($this->form['#conditional_fields'][$dependee])) {
+        continue;
+      }
 
-        // Add validation callback to element if the dependency can be evaluated.
-        if (in_array($options['condition'], [
-          'value',
-          'empty',
-          '!empty',
-          'checked',
-          '!checked',
-        ])) {
-        self::elementAddProperty($dependent_form_field, '#element_validate', [self::class, 'dependentValidate'], 'append');
-        }
+      $dependee_info = $this->form['#conditional_fields'][$dependee];
 
-        self::addStateToGroup($states, $state, $options);
+      end($dependee_info['parents']);
+      $unset = key($dependee_info['parents']);
+      if (is_int($dependee_info['parents'][$unset]) && $dependee_info['parents'][$unset] > 0) {
+        unset($dependee_info['parents'][$unset]);
+      }
 
-        $selector = conditional_fields_field_selector(NestedArray::getValue($form, [$dependent_location[0]]));
-        $effects[$selector] = self::getEffect($options);
+      $dependee_form_field = NestedArray::getValue($this->form, $dependee_info['parents']);
+      $options = $dependency['options'];
 
+      if (!empty($options['values']) && is_string($options['values'])) {
+        $options['values'] = explode("\r\n", $options['values']);
       }
 
-      if (empty($states)) {
-        continue;
+      $options['selector'] = self::getSelector($options['selector'], $dependee_form_field);
+
+      $state = $this->getState($dependee, $dependee_form_field, $options);
+
+      // Add validation callback to element if the dependency can be evaluated.
+      if (in_array($options['condition'], [
+        'value',
+        'empty',
+        '!empty',
+        'checked',
+        '!checked',
+      ])) {
+      self::elementAddProperty($this->dependent_form_field, '#element_validate', [self::class, 'dependentValidate'], 'append');
       }
 
-      // Save the modified field back into the form.
-      NestedArray::setValue($form, $dependent_location, $dependent_form_field);
+      $this->addStateToGroup($state, $options);
 
-      // Add the #states property to the dependent field.
-      $states = self::mapStates($states);
-      NestedArray::setValue($form, array_merge($dependent_location, ['#states']), $states);
+      $selector = conditional_fields_field_selector(NestedArray::getValue($this->form, [$this->dependent_location[0]]));
+      $this->effects[$selector] = self::getEffect($options);
     }
+  }
 
-    $form['#attached']['library'][] = 'conditional_fields/conditional_fields';
+  /**
+   * Add our Javascript and effects.
+   */
+  protected function addJavascriptEffects() {
+    $this->form['#attached']['library'][] = 'conditional_fields/conditional_fields';
     // Add effect settings to the form.
-    if ($effects) {
-      $form['#attached']['drupalSettings']['conditionalFields'] = [
-        'effects' => $effects,
+    if ($this->effects) {
+      $this->form['#attached']['drupalSettings']['conditionalFields'] = [
+        'effects' => $this->effects,
       ];
     }
-
-    // Validation callback to manage dependent fields validation.
-    $form['#validate'][] = [self::class, 'formValidate'];
-    // Initialize validation information every time the form is rendered to avoid
-    // stale data after a failed submission.
-    $form_state->setValue('conditional_fields_untriggered_dependents', []);
-
-    return $form;
   }
 
   /**
-   * Build a jQuery selector if it was not overridden by a custom value.
-   *
-   * Note that this may be overridden later by a state handler.
+   * Add validation callback to manage dependent fields validation.
    */
-  protected static function getSelector($options_selector, $dependee_form_field) {
-    if (!$options_selector) {
-      $selector = conditional_fields_field_selector($dependee_form_field);
-    }
-    else {
-      // Replace the language placeholder in the selector with current language.
-      $selector = str_replace('%lang', $dependee_form_field['#language'], $options_selector);
-    }
-    return $selector;
+  protected function addValidationCallback() {
+    $this->form['#validate'][] = [self::class, 'formValidate'];
+    // Initialize validation information every time the form is rendered to avoid
+    // stale data after a failed submission.
+    $this->form_state->setValue('conditional_fields_untriggered_dependents', []);
   }
 
   /**
    * Get list of states for the pair from the options.
    *
-   * @param EntityFormDisplayInterface $form_display
-   *   Form display.
    * @param string $dependee
    *   Machine name of control field.
    * @param array $dependee_form_field
    *   Nested array of control field.
    * @param array $options
    *   Settings of dependency.
-   * @param FormStateInterface $form_state
-   *   Form state interface
    * @return array
    *   List of states.
    *
    * @see hook_get_state
    */
-  protected static function getState(EntityFormDisplayInterface $form_display, $dependee, $dependee_form_field, $options, $form_state = NULL) {
+  protected function getState($dependee, $dependee_form_field, $options) {
+    // @var EntityFormDisplayInterface $form_display
+    $form_display = $this->form_state->getFormObject()->getFormDisplay($this->form_state);
     $state = [];
     /** @var \Drupal\conditional_fields\ConditionalFieldsHandlersManager $type */
     $type = \Drupal::service('plugin.manager.conditional_fields_handlers');
@@ -164,7 +176,7 @@ class ConditionalFieldsFormHelper {
     }
     else {
       $field_name = explode('[', $dependee_form_field['#name']);
-      $dependee_form_state = isset($dependee_form_field['#field_parents'], $field_name[0], $form_state) ? WidgetBase::getWidgetState($dependee_form_field['#field_parents'], $field_name[0], $form_state) : NULL;
+      $dependee_form_state = isset($dependee_form_field['#field_parents'], $field_name[0], $this->form_state) ? WidgetBase::getWidgetState($dependee_form_field['#field_parents'], $field_name[0], $this->form_state) : NULL;
       $dependee_form_field['#original_name'] = $field_name[0];
       $dependee_display = $form_display->getComponent($dependee);
       if (is_array($dependee_display) && array_key_exists('type', $dependee_display)) {
@@ -200,24 +212,49 @@ class ConditionalFieldsFormHelper {
     return $state;
   }
 
+  protected function hasConditionalFields() {
+    // Dependencies data is attached in conditional_fields_element_after_build().
+    if (empty($this->form['#conditional_fields'])) {
+      return FALSE;
+    }
+    if (!method_exists($this->form_state->getFormObject(), 'getFormDisplay')) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  /**
+   * Build a jQuery selector if it was not overridden by a custom value.
+   *
+   * Note that this may be overridden later by a state handler.
+   */
+  protected static function getSelector($options_selector, $dependee_form_field) {
+    if (!$options_selector) {
+      $selector = conditional_fields_field_selector($dependee_form_field);
+    }
+    else {
+      // Replace the language placeholder in the selector with current language.
+      $selector = str_replace('%lang', $dependee_form_field['#language'], $options_selector);
+    }
+    return $selector;
+  }
+
   /**
    * Merge field states to general list.
    *
-   * @param array $states
-   *   List of all form states.
    * @param array $state
    *   List of field states.
    * @param array $options
    *   Field CF settings.
    */
-  protected static function addStateToGroup(&$states, $state, $options) {
+  protected function addStateToGroup($state, $options) {
     // Add the $state into the correct logic group in $states.
     foreach ($state as $key => $constraints) {
-      if (empty($states[$key][$options['grouping']])) {
-        $states[$key][$options['grouping']] = $constraints;
+      if (empty($this->states[$key][$options['grouping']])) {
+        $this->states[$key][$options['grouping']] = $constraints;
       }
       else {
-        $states[$key][$options['grouping']] = array_merge($states[$key][$options['grouping']], $constraints);
+        $this->states[$key][$options['grouping']] = array_merge($this->states[$key][$options['grouping']], $constraints);
       }
     }
   }
@@ -673,7 +710,7 @@ class ConditionalFieldsFormHelper {
    *   the $element[$property] array, any other value to insert it
    *   at the beginning.
    */
-  public static function elementAddProperty(&$element, $property, $value, $position = 'prepend') {
+  public function elementAddProperty(&$element, $property, $value, $position = 'prepend') {
     // Avoid overriding default element properties that might not yet be set.
     if (!isset($element[$property])) {
       $element[$property] = isset($element['#type']) ? element_info_property($element['#type'], $property, []) : [];
@@ -698,35 +735,29 @@ class ConditionalFieldsFormHelper {
 
   /**
    * Map the states based on the conjunctions.
-   *
-   * @param array $states
-   *   States to map.
-   *
-   * @return array
-   *   Mapped states.
    */
-  protected static function mapStates($states) {
+  protected function mapStates() {
     $states_new = [];
-    foreach ($states as $state_key => $value) {
+    foreach ($this->states as $state_key => $value) {
       // As the main object is ANDed together we can add the AND items directly.
-      if (!empty($states[$state_key]['AND'])) {
-        $states_new[$state_key] = $states[$state_key]['AND'];
+      if (!empty($this->states[$state_key]['AND'])) {
+        $states_new[$state_key] = $this->states[$state_key]['AND'];
       }
       // The OR and XOR groups are moved into a sub-array that has numeric keys
       // so that we get a JSON array and not an object, as required by the States
       // API for OR and XOR groupings.
-      if (!empty($states[$state_key]['OR'])) {
+      if (!empty($this->states[$state_key]['OR'])) {
         $or = [];
-        foreach ($states[$state_key]['OR'] as $constraint_key => $constraint_value) {
+        foreach ($this->states[$state_key]['OR'] as $constraint_key => $constraint_value) {
           $or[] = [$constraint_key => $constraint_value];
         }
         // '1' as a string so that we get an object (which means logic groups
         // are ANDed together).
         $states_new[$state_key]['1'] = $or;
       }
-      if (!empty($states[$state_key]['XOR'])) {
+      if (!empty($this->states[$state_key]['XOR'])) {
         $xor = ['xor'];
-        foreach ($states[$state_key]['XOR'] as $constraint_key => $constraint_value) {
+        foreach ($this->states[$state_key]['XOR'] as $constraint_key => $constraint_value) {
           $xor[] = [$constraint_key => $constraint_value];
         }
         // '2' as a string so that we get an object.
diff --git a/src/DependencyHelper.php b/src/DependencyHelper.php
new file mode 100644
index 0000000..09cfd49
--- /dev/null
+++ b/src/DependencyHelper.php
@@ -0,0 +1,244 @@
+<?php
+
+namespace Drupal\conditional_fields;
+
+/**
+ * Resolve conditional field's dependencies.
+ */
+class DependencyHelper {
+
+  /* The current entity type. */
+  protected $entity_type;
+
+  /* The current bundle name. */
+  protected $bundle;
+
+  /* Name of the current dependent field. */
+  protected $dependent;
+
+  /* The current dependent field. */
+  protected $dependent_field;
+
+  /* Full list of dependencies. */
+  protected $dependencies;
+
+  /* Dependent field definitions. */
+  protected $dependent_fields;
+
+  /* UUID of the current dependency. */
+  protected $uuid;
+
+  /* Name of the current dependee field. */
+  protected $dependee;
+
+  /* Options that define the current dependency. */
+  protected $settings;
+
+  /**
+   * Return dependencies.
+   */
+  public function getDependencies($entity_type = NULL, $bundle = NULL) {
+    $this->entity_type = $entity_type;
+    $this->bundle = $bundle;
+
+    $this->resolveBundleDependencies();
+
+    if ($this->bundleProcessed()) {
+      return $this->getBundleDependencies();
+    }
+
+    if ($this->entityTypeProcessed()) {
+      return $this->getEntityTypeDependencies();
+    }
+
+    return $this->dependencies;
+  }
+
+  /**
+   * Resolve all dependencies.
+   */
+  protected function resolveBundleDependencies() {
+    if ($this->bundleProcessed()) return;
+    $this->resolveDependencies($this->getBundleDependentFields());
+  }
+
+  /**
+   * Resolve a bundle's dependencies.
+   */
+  protected function resolveDependencies($dependent_fields) {
+    foreach ($dependent_fields as $dependent => $field) {
+      $this->dependent = $dependent;
+      $this->dependent_field = $field;
+      $this->resolveFieldDependencies();
+    }
+  }
+
+  /**
+   * Resolve a field's dependencies.
+   */
+  protected function resolveFieldDependencies() {
+    foreach ($this->dependent_field['third_party_settings']['conditional_fields'] as $uuid => $conditional_field) {
+      $this->uuid = $uuid;
+      $this->dependee = $conditional_field['dependee'];
+      $this->settings = $conditional_field['settings'];
+      if ($this->fieldDependencyShouldPropagate()) {
+        $this->resolveDependencies($this->getInheritingFields());
+        // @TODO Add setting to allow the conditional field to apply to the parent.
+        continue;
+      }
+      $this->registerFieldDependency();
+    }
+  }
+
+  /**
+   * Determine whether a field dependency should be inherited.
+   */
+  protected function fieldDependencyShouldPropagate() {
+    if (!isset($this->settings['inheritance']['propagate'])) return FALSE;
+    return (bool) $this->settings['inheritance']['propagate'];
+  }
+
+  /**
+   * Return fields with conditional settings to inherit.
+   */
+  protected function getInheritingFields() {
+    $propagating_settings = $this->dependent_field['third_party_settings']['conditional_fields'][$this->uuid];
+    // @TODO Add setting to allow recursion on those fields that'd support it?
+    // @TODO Fix that this currently overrides whatever settings already exist in the field's config.
+    $propagating_settings['settings']['inheritance']['propagate'] = FALSE;
+    $bundle_fields = $this->getBundleFields();
+    $inheriting_fields = [];
+    foreach ($this->getInheritingFieldNames() as $field_name) {
+      $inheriting_field = $bundle_fields[$field_name];
+      $inheriting_field['third_party_settings']['conditional_fields'][$this->uuid] = $propagating_settings;
+      $inheriting_fields[$field_name] = $inheriting_field;
+    }
+    return $inheriting_fields;
+  }
+
+  /**
+   * Return a list of fields to inherit conditional settings.
+   */
+  protected function getInheritingFieldNames() {
+    $module_handler = \Drupal::moduleHandler();
+    $hook = 'conditional_fields_children';
+    $children = $module_handler
+      ->invokeAll($hook, [$this->entity_type, $this->bundle, $this->dependent]);
+    $module_handler
+      ->alter($hook, $children, $this->entity_type, $this->bundle, $this->dependent);
+    return $children;
+  }
+
+  /**
+   * Register a specific conditional field dependency.
+   */
+  protected function registerFieldDependency() {
+    $this->registerDependent();
+    $this->registerDependee();
+  }
+
+  /**
+   * Add a dependent field to the list of dependencies.
+   */
+  protected function registerDependent() {
+    $this->dependencies[$this->entity_type][$this->bundle]['dependents'][$this->dependent][$this->uuid] = [
+      'dependee' => $this->dependee,
+      'options' => $this->settings,
+    ];
+  }
+
+  /**
+   * Add a dependee field to the list of dependencies.
+   */
+  protected function registerDependee() {
+    $this->dependencies[$this->entity_type][$this->bundle]['dependees'][$this->dependee][$this->uuid] = [
+      'dependent' => $this->dependent,
+      'options' => $this->settings,
+    ];
+  }
+
+  /**
+   * Determine whether a bundle has dependencies.
+   */
+  protected function bundleProcessed() {
+    if (!$this->entityTypeProcessed()) return FALSE;
+    if (is_null($this->bundle)) return FALSE;
+    return isset($this->dependencies[$this->entity_type][$this->bundle]);
+  }
+
+  /**
+   * Determine whether an entity type has dependencies.
+   */
+  protected function entityTypeProcessed() {
+    if (is_null($this->entity_type)) return FALSE;
+    return isset($this->dependencies[$this->entity_type]);
+  }
+
+  /**
+   * Return dependencies for a bundle.
+   */
+  protected function getBundleDependencies() {
+    return $this->dependencies[$this->entity_type][$this->bundle];
+  }
+
+  /**
+   * Return dependencies for an entity type.
+   */
+  protected function getEntityTypeDependencies() {
+    return $this->dependencies[$this->entity_type];
+  }
+
+  /**
+   * Return all dependent fields attached to a bundle.
+   */
+  protected function getBundleDependentFields() {
+    if (!$this->BundleHasRegisteredDependentFields()) {
+      $this->registerBundleDependentFields();
+    }
+    return $this->dependent_fields[$this->entity_type][$this->bundle];
+  }
+
+  /**
+   * Determine whether a bundle has registered any dependent fields.
+   */
+  protected function BundleHasRegisteredDependentFields() {
+    if (!isset($this->dependent_fields[$this->entity_type][$this->bundle])) return FALSE;
+    if (empty($this->dependent_fields[$this->entity_type][$this->bundle])) return FALSE;
+    return TRUE;
+  }
+
+  /**
+   * Register all dependent fields attached to a bundle.
+   */
+  protected function registerBundleDependentFields() {
+    $this->dependent_fields[$this->entity_type][$this->bundle] = [];
+    foreach ($this->getBundleFields() as $name => $field) {
+      if (!$this->hasConditionalFields($field)) continue;
+      $this->dependent_fields[$this->entity_type][$this->bundle][$name] = $field;
+    }
+  }
+
+  /**
+   * Return all fields attached to a bundle.
+   */
+  protected function getBundleFields() {
+    /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity */
+    $entity = \Drupal::entityTypeManager()
+      ->getStorage('entity_form_display')
+      ->load($this->entity_type . '.' . $this->bundle . '.default');
+
+    if (!$entity) {
+      return [];
+    }
+
+    return $entity->getComponents();
+  }
+
+  /**
+   * Determine whether a field has any conditional fields defined.
+   */
+  protected function hasConditionalFields($field) {
+    return !empty($field['third_party_settings']['conditional_fields']);
+  }
+
+}
diff --git a/src/Form/ConditionalFieldEditForm.php b/src/Form/ConditionalFieldEditForm.php
index 3c56ccd..addbeb3 100644
--- a/src/Form/ConditionalFieldEditForm.php
+++ b/src/Form/ConditionalFieldEditForm.php
@@ -250,6 +250,14 @@ class ConditionalFieldEditForm extends FormBase {
       '#required' => TRUE,
     ];
 
+    $form['inheritance'] = [
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Inheritance'),
+      '#description' => $this->t('This element contains other fields. Apply the settings in this form to the contained fields instead of this one.'),
+      '#options' => ['propagate' => 'Propagate settings to fields contained within this one.'],
+      '#default_value' => array_key_exists('inheritance', $settings) ? $settings['inheritance'] : [],
+    ];
+
     $form['entity_edit'] = [
       '#type' => 'details',
       '#title' => $this->t('Edit context settings'),
diff --git a/src/Form/ConditionalFieldForm.php b/src/Form/ConditionalFieldForm.php
index b6f9c6b..e9bf4fd 100644
--- a/src/Form/ConditionalFieldForm.php
+++ b/src/Form/ConditionalFieldForm.php
@@ -10,6 +10,7 @@ use Drupal\conditional_fields\Conditions;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 
 /**
  * Class ConditionalFieldForm.
@@ -50,6 +51,26 @@ class ConditionalFieldForm extends FormBase {
    */
   protected $list;
 
+  /**
+   * Form array.
+   */
+  protected $form;
+
+  /**
+   * FormState object.
+   */
+  protected $form_state;
+
+  /**
+   * Name of the entity type being configured.
+   */
+  protected $entity_type;
+
+  /**
+   * Name of the entity bundle being configured.
+   */
+  protected $bundle_name;
+
   /**
    * Class constructor.
    *
@@ -61,12 +82,21 @@ class ConditionalFieldForm extends FormBase {
    *   Provides an interface for entity type managers.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid
    *   Uuid generator.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   Manages modules in a Drupal installation.
    */
-  public function __construct(Conditions $list, EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, UuidInterface $uuid) {
+  public function __construct(
+    Conditions $list,
+    EntityFieldManagerInterface $entity_field_manager,
+    EntityTypeManagerInterface $entity_type_manager,
+    UuidInterface $uuid,
+    ModuleHandlerInterface $module_handler
+  ) {
     $this->entityFieldManager = $entity_field_manager;
     $this->entityTypeManager = $entity_type_manager;
     $this->list = $list;
     $this->uuidGenerator = $uuid;
+    $this->module_handler = $module_handler;
   }
 
   /**
@@ -79,7 +109,8 @@ class ConditionalFieldForm extends FormBase {
       $container->get('conditional_fields.conditions'),
       $container->get('entity_field.manager'),
       $container->get('entity_type.manager'),
-      $container->get('uuid')
+      $container->get('uuid'),
+      $container->get('module_handler')
     );
   }
 
@@ -94,20 +125,24 @@ class ConditionalFieldForm extends FormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state, $entity_type = NULL, $bundle = NULL) {
+    $this->form = $form;
+    $this->form_state = $form_state;
+    $this->entity_type = $entity_type;
+    $this->bundle_name = $bundle;
 
-    $form['entity_type'] = [
+    $this->form['entity_type'] = [
       '#type' => 'hidden',
-      '#value' => $entity_type,
+      '#value' => $this->entity_type,
     ];
 
-    $form['bundle'] = [
+    $this->form['bundle'] = [
       '#type' => 'hidden',
-      '#value' => $bundle,
+      '#value' => $this->bundle_name,
     ];
 
-    $form['conditional_fields_wrapper']['table'] = $this->buildTable($form, $form_state, $entity_type, $bundle);
+    $this->buildTable();
 
-    return $form;
+    return $this->form;
   }
 
   /**
@@ -138,6 +173,7 @@ class ConditionalFieldForm extends FormBase {
         // Validate required field should be visible.
         $field_instance = $instances[$field];
         if (
+          method_exists($field_instance, 'isRequired') &&
           $field_instance->isRequired() &&
           in_array($state, ['!visible', 'disabled', '!required'])
         ) {
@@ -227,11 +263,11 @@ class ConditionalFieldForm extends FormBase {
   /**
    * Builds table with conditional fields.
    */
-  protected function buildTable(array $form, FormStateInterface $form_state, $entity_type, $bundle_name = NULL) {
-    $form['table'] = [
+  protected function buildTable() {
+    $table = [
       '#type' => 'table',
-      '#entity_type' => $entity_type,
-      '#bundle_name' => $bundle_name,
+      '#entity_type' => $this->entity_type,
+      '#bundle_name' => $this->bundle_name,
       '#header' => [
         $this->t('Target field'),
         $this->t('Controlled by'),
@@ -240,25 +276,18 @@ class ConditionalFieldForm extends FormBase {
       ],
     ];
 
-    // Build list of available fields.
-    $fields = [];
-    $instances = $this->entityFieldManager
-      ->getFieldDefinitions($entity_type, $bundle_name);
-    foreach ($instances as $field) {
-      $fields[$field->getName()] = $field->getLabel() . ' (' . $field->getName() . ')';
-    }
-
-    asort($fields);
+    $fields = $this->getFieldsList();
 
     /* Existing conditions. */
 
     /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display_entity */
     $form_display_entity = $this->entityTypeManager
       ->getStorage('entity_form_display')
-      ->load("$entity_type.$bundle_name.default");
+      ->load("$this->entity_type.$this->bundle_name.default");
 
     if (!$form_display_entity) {
-      return $form['table'];
+      $this->form['conditional_fields_wrapper']['table'] = $table;
+      return;
     }
 
     foreach ($fields as $field_name => $label) {
@@ -275,7 +304,7 @@ class ConditionalFieldForm extends FormBase {
           'uuid' => $uuid,
         ];
 
-        $form['table'][] = [
+        $table[] = [
           'dependent' => ['#markup' => $field_name],
           'dependee' => ['#markup' => $condition['dependee']],
           'state' => ['#markup' => $condition['settings']['state']],
@@ -310,7 +339,7 @@ class ConditionalFieldForm extends FormBase {
     }
 
     // Add new dependency row.
-    $form['table']['add_new_dependency'] = [
+    $table['add_new_dependency'] = [
       'dependent' => [
         '#type' => 'select',
         '#multiple' => TRUE,
@@ -359,9 +388,31 @@ class ConditionalFieldForm extends FormBase {
       ],
     ];
 
-    $form['table']['#attached']['library'][] = 'conditional_fields/admin';
+    $table['#attached']['library'][] = 'conditional_fields/admin';
 
-    return $form['table'];
+    $this->form['conditional_fields_wrapper']['table'] = $table;
+  }
+
+  /**
+   * Return available fields.
+   */
+  protected function getFields() {
+    $fields = $this->module_handler
+      ->invokeAll('conditional_fields', [$this->entity_type, $this->bundle_name]);
+    $this->module_handler
+      ->alter('conditional_fields',$fields, $this->entity_type, $this->bundle_name);
+    return $fields;
+  }
+
+  /**
+   * Build options list of available fields.
+   */
+  protected function getFieldsList() {
+    $fields = [];
+    foreach ($this->getFields() as $name => $label) {
+      $fields[$name] = $label . ' (' . $name . ')';
+    }
+    return $fields;
   }
 
 }
