Drupal 8: How to properly add a settings widget to a node add/edit form and save the value?
I'm going to take a stab and show how I solved it, but I'm still curious to know if there's a better way.

In a nutshell, I used hook_form_BASE_FORM_ID_alter(), hook_node_submit(), and hook_ENTITY_TYPE_insert() or hook_ENTITY_TYPE_update() in the .module file.

Then I have a class called HierarchyManager that does all the heavy lifting that the D7 .module and .inc files used to do. It's listed as a service named "nodehierarchy.manager".

Lastly, I have a class called HierarchyOutlineStorage that handles the database inserts and updates. Quite a bit of that code was copied directly from D7. 

In my .module file:

/**
 * Implements hook_form_BASE_FORM_ID_alter() for node_form().
 *
 * Adds the hierarchy form element to the node form.
 */
function nodehierarchy_form_node_form_alter(&amp;$form, FormStateInterface $form_state, $form_id) {

  // Load the node object associated with this form
  $node = $form_state-&gt;getFormObject()-&gt;getEntity();
  $account = \Drupal::currentUser();

  // Optional but keeps the .module code cleaner IMO      
  $hierarchy_manager = \Drupal::service('nodehierarchy.manager');

  // Do your permission checks here
  $has_permission = ...;
  if($has_permission) {
    $form = $hierarchy_manager-&gt;addHierarchyFormElement($form, $form_state, $node, $account, $collapsed);
  } 
}

/**
 * Implements hook_node_submit().
 */
function nodehierarchy_node_submit(NodeInterface $node, $form, FormStateInterface $form_state) {
  // Here the node object gets updated with the form value to be used later
  // If you aren't sure about the $form_state, download/enable devel and add
  // dsm($form_state-&gt;getValues()) to show all available values
  if (!$form_state-&gt;isValueEmpty('nodehierarchy_parents')) {
    $node-&gt;nodehierarchy_parents = $form_state-&gt;getValue('nodehierarchy_parents');
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert() for node entities.
 *
 * Save the form settings
 */
function nodehierarchy_node_insert(NodeInterface $node) {
  $hierarchy_manager = \Drupal::service('nodehierarchy.manager');
  $has_permission = ...
  if ($has_permisson) {
    $hierarchy_manager-&gt;hierarchySaveNode($node);
  }
}

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function nodehierarchy_node_update(EntityInterface $node) {
  $hierarchy_manager = \Drupal::service('nodehierarchy.manager');
  $hierarchy_manager-&gt;hierarchySaveNode($node);
}


In the HierarchyManager.php file:

public function addHierarchyFormElement(array $form, FormStateInterface $form_state, NodeInterface $node, AccountInterface $account, $collapsed = TRUE) {
  // Insert $form array here
  $form['hierarchy'] = array(...);
}

public function hierarchySaveNode(&amp;$node) {
  // Do all your processing here, then insert or update dB record
  $isNew = ...
  if ($isNew) {
    return $this-&gt;hierarchyOutlineStorage-&gt;insert($item);  
  }
  else {
    return $this-&gt;hierarchyOutlineStorage-&gt;update($item-&gt;hid, $item);
  }
}