Loading taxonomy terms in a tree in Drupal 8
TermForm.php has an example of how to do this.

Basically you loop through the tree and add dashes according to the depth of the term.

Here's an example you can use:

$options = [];
foreach (\Drupal::entityTypeManager()-&gt;getStorage('taxonomy_term')-&gt;loadTree($vid) as $item) {
  $options[$item-&gt;tid] = str_repeat('-', $item-&gt;depth) . $item-&gt;name;
}


UPDATE: If you want a nested array of terms, you can do like this:

$result = [];
foreach (\Drupal::entityTypeManager()-&gt;getStorage('taxonomy_term')-&gt;loadTree($vid) as $item) {
  $parents = array_reverse(\Drupal::entityTypeManager()-&gt;getStorage('taxonomy_term')-&gt;loadAllParents($item-&gt;tid), TRUE);
  $r = &amp;$result;
  foreach ($parents as $k =&gt; $v) {
    if (isset($r[$k])) {
      $r[$k] = array_replace($r[$k], [$k =&gt; $v-&gt;label()]);
    }
    else {
      $r[$k] = [$k =&gt; $v-&gt;label()];
    }
    $r = &amp;$r[$k];
  }
}


That will work regardless of how many levels your terms are nested.