diff --git a/src/EntityClone/Content/ContentEntityCloneBase.php b/src/EntityClone/Content/ContentEntityCloneBase.php
index 58fa2396424c0c584984fb142590f27397f23720..9302151584f081a89ba3fc670a96bd6585ddc610 100644
--- a/src/EntityClone/Content/ContentEntityCloneBase.php
+++ b/src/EntityClone/Content/ContentEntityCloneBase.php
@@ -13,6 +13,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\TranslatableInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Field\FieldConfigInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Session\AccountProxyInterface;
@@ -60,6 +61,13 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
    */
   protected $currentUser;
 
+  /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
   /**
    * Constructs a new ContentEntityCloneBase.
    *
@@ -73,13 +81,16 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
    *   The current user.
    * @param \Drupal\entity_clone\EntityCloneClonableFieldInterface $entity_clone_clonable_field
    *   The entity clone clonable field service.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, string $entity_type_id, TimeInterface $time_service, AccountProxyInterface $current_user, EntityCloneClonableFieldInterface $entity_clone_clonable_field) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, string $entity_type_id, TimeInterface $time_service, AccountProxyInterface $current_user, EntityCloneClonableFieldInterface $entity_clone_clonable_field, ModuleHandlerInterface $module_handler) {
     $this->entityTypeManager = $entity_type_manager;
     $this->entityTypeId = $entity_type_id;
     $this->timeService = $time_service;
     $this->currentUser = $current_user;
     $this->entityCloneClonableField = $entity_clone_clonable_field;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -91,7 +102,8 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
       $entity_type->id(),
       $container->get('datetime.time'),
       $container->get('current_user'),
-      $container->get('entity_clone.clonable_field')
+      $container->get('entity_clone.clonable_field'),
+      $container->get('module_handler')
     );
   }
 
@@ -99,6 +111,25 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
    * {@inheritdoc}
    */
   public function cloneEntity(EntityInterface $entity, EntityInterface $cloned_entity, array $properties = [], array &$already_cloned = []) {
+    // Clone books entities.
+    $bid = isset($entity->book) && empty($entity->book['bid']) ? 0 : $entity->book['bid'];
+    if (!empty($properties['clone_book']) && !empty($bid) && $entity->book['bid'] == $entity->id()) {
+      // This is the parent book.
+      $link = [
+        'nid' => $cloned_entity->id(),
+        'bid' => 'new',
+        'pid' => 0,
+        'has_children' => $entity->book['has_children'],
+        'weight' => 0,
+        'depth' => 1,
+      ];
+      $cloned_entity->book = $link;
+      $cloned_entity->save();
+
+      // Clone book children.
+      $this->cloneBookPages($entity, $cloned_entity, $properties);
+    }
+
     // Clone referenced entities.
     $already_cloned[$entity->getEntityTypeId()][$entity->id()] = $cloned_entity;
     if ($cloned_entity instanceof FieldableEntityInterface && $entity instanceof FieldableEntityInterface) {
@@ -122,7 +153,10 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
       }
     }
 
-    $this->setClonedEntityLabel($entity, $cloned_entity, $properties);
+    // Only change the label on single nodes, fixing the title on entire books is too cumbersome.
+    if (empty($properties['clone_book'])) {
+      $this->setClonedEntityLabel($entity, $cloned_entity, $properties);
+    }
     $this->setCreatedAndChangedDates($cloned_entity);
 
     if ($this->hasTranslatableModerationState($cloned_entity)) {
@@ -365,4 +399,66 @@ class ContentEntityCloneBase implements EntityHandlerInterface, EntityCloneInter
     }
   }
 
+  /**
+   * Clone the book pages within a book.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $original_entity
+   *   The original entity.
+   * @param \Drupal\Core\Entity\EntityInterface $cloned_entity
+   *   The entity cloned from the original.
+   * @param array $properties
+   *   The properties argument containing the bid and nid map.
+   */
+  protected function cloneBookPages(EntityInterface $original_entity, EntityInterface $cloned_entity, array $properties) {
+    $bid = $cloned_entity->id();
+    $map = [
+      $original_entity->id() => $cloned_entity->id(),
+    ];
+
+    $children = \Drupal::service('book.outline_storage')->loadBookChildren($original_entity->id());
+    $this->cloneBookChildren($children, $properties, $bid, $map);
+  }
+
+  /**
+   * Recursive method to walk the children and clone.
+   *
+   * @param array $children
+   *   The current pages children.
+   * @param array $properties
+   *   The properties argument containing the bid and nid map.
+   * @param int $bid
+   *   The book id.
+   * @param array $map
+   *   The map argument containing the old nid to new map to set the new parent properly.
+   */
+  protected function cloneBookChildren(array $children, array $properties, int $bid, array &$map) {
+    foreach ($children as $nid => $child) {
+      $entity = $this->entityTypeManager->getStorage('node')->load($nid);
+      $duplicate = $entity->createDuplicate();
+      $cloned_entity = $this->cloneEntity($entity, $duplicate, $properties);
+
+      // Set the moderation state in children books according to user's choice.
+      if ($this->moduleHandler->moduleExists('content_moderation') && isset($properties['moderation_state']) && $duplicate->hasField('moderation_state')) {
+        $duplicate->set('moderation_state', $properties['moderation_state']);
+      }
+
+      $link = [
+        'nid' => $cloned_entity->id(),
+        'bid' => $bid,
+        'pid' => !empty($map[$entity->book['pid']]) ? $map[$entity->book['pid']] : $bid,
+        'weight' => $entity->book['weight'],
+        'depth' => $entity->book['depth'],
+      ];
+      $cloned_entity->book = $link;
+      $cloned_entity->save();
+
+      $map[$entity->id()] = $cloned_entity->id();
+
+      if ($child['has_children'] == 1) {
+        $next_level = \Drupal::service('book.outline_storage')->loadBookChildren($nid);
+        $this->cloneBookChildren($next_level, $properties, $bid, $map);
+      }
+    }
+  }
+
 }
diff --git a/src/EntityClone/Content/ContentEntityCloneFormBase.php b/src/EntityClone/Content/ContentEntityCloneFormBase.php
index fe5963926c7d03a87e6dd0fb19f69f68258897da..ddaa28008184085dc1760494c4b3f511fc91eb8b 100644
--- a/src/EntityClone/Content/ContentEntityCloneFormBase.php
+++ b/src/EntityClone/Content/ContentEntityCloneFormBase.php
@@ -125,6 +125,25 @@ class ContentEntityCloneFormBase implements EntityHandlerInterface, EntityCloneF
             '#access' => TRUE,
           ],
         ], $form);
+
+        $bid = !empty($entity->book['bid']) ? $entity->book['bid'] : 0;
+        if (!empty($bid) && $entity->id() == $bid) {
+          $form['book'] = [
+            '#type' => 'fieldset',
+            '#weight' => -5,
+          ];
+
+          $form['book']['description'] = [
+            '#type' => 'markup',
+            '#markup' => t('This is a top-level book. Select the checkbox below to clone all of the pages within the book.'),
+          ];
+
+          $form['book']['clone_book'] = [
+            '#type' => 'checkbox',
+            '#title' => t('Clone entire book including child pages'),
+            '#default_value' => 0,
+          ];
+        }
       }
     }