diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -748,9 +748,75 @@
         $slug->delete();
       }
 
+      // Destroy my milestones because they cannot live without me.
+      // Do not use PhabricatorProjectQuery to avoid a circular dependency,
+      // and, to do not have a load silent fail, since these milestones do not
+      // have their parent anymore.
+      $milestones = id(new self())
+        ->loadAllWhere('parentProjectPHID = %s AND milestoneNumber IS NOT NULL',
+        $this->getPHID());
+      foreach ($milestones as $milestone) {
+        $milestone->attachParentProject($this);
+        $engine->destroyObject($milestone);
+      }
+
+      // Update my children to eventually fix holes in the tree.
+      $this->onDestroyTouchChildren(true);
+
+      // After the tree is fixed, update my parent hasSubProjects field.
+      if ($this->getParentProject()) {
+        id(new PhabricatorProjectsMembershipIndexEngineExtension())
+          ->rematerialize($this->getParentProject());
+      }
+
     $this->saveTransaction();
   }
 
+  /**
+   * On destroy, eventually bubble up my direct children, to take my place.
+   * Refresh all remaining children, to consolidate depth, path key, etc.
+   */
+  private function onDestroyTouchChildren($close_my_hole) {
+    // Micro-optimization.
+    if (!$this->supportsSubprojects() && !$this->supportsMilestones()) {
+      return;
+    }
+
+    // Get direct sub-projects and milestones and their new desired parent.
+    // We must skip my direct milestones since they are under removal.
+    // Do not use PhabricatorProjectQuery to avoid a circular dependency.
+    $query_children = new self();
+    if ($close_my_hole) {
+      $desired_parent = $this->getParentProject();
+      $children = $query_children->loadAllWhere(
+        'parentProjectPHID = %s AND milestoneNumber IS NULL',
+        $this->getPHID());
+    } else {
+      $desired_parent = $this;
+      $children = $query_children->loadAllWhere(
+        'parentProjectPHID = %s',
+        $this->getPHID());
+    }
+
+    // The desired parent PHID for my children may become NULL,
+    // when we are closing my hole but my parent it's a root-project.
+    $desired_parent_phid = null;
+    if ($desired_parent) {
+      $desired_parent_phid = $desired_parent->getPHID();
+    }
+
+    // Eventually bubble up my direct children. Update the others.
+    foreach ($children as $child) {
+      $child->attachParentProject($desired_parent);
+      $child->setParentProjectPHID($desired_parent_phid);
+      $child->setProjectPathKey(null); // Force a new path key and depth.
+      $child->save();
+
+      // Descend the tree.
+      $child->onDestroyTouchChildren(false);
+    }
+  }
+
 
 /* -(  PhabricatorFulltextInterface  )--------------------------------------- */