diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index beef1d66822a1ee1df474dab65c2b2a7f33a36cc..a36aee80100e37084915b49f6ab772ba037a44e1 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -878,11 +878,52 @@ export class PabTableComponent implements AfterViewInit, OnInit {
     }
 
     public get enableRemoveButton() {
+        let containsDownwall = false;
+        let containsOrphanNub = false;
+        let tooFewDevices = false;
+        let wallsCount = 0;
+        const devicesCountById = {};
+        const deletedWallsUids = [];
+
+        for (const se of this.selectedItems) {
+            if (se instanceof Structure) { // device
+                if (devicesCountById[se.parent.uid] === undefined) {
+                    devicesCountById[se.parent.uid] = 0;
+                }
+                devicesCountById[se.parent.uid]++;
+            } else { // wall
+                wallsCount++;
+                deletedWallsUids.push(se.uid);
+            }
+            if (se instanceof CloisonAval) {
+                containsDownwall = true; // cannot remove downwall
+            }
+            if (! se.parent) {
+                containsOrphanNub = true; // not supposed to happen but who knows
+            }
+        }
+
+        // at least one device must remain in each basin, unless this basin is removed too
+        for (const structureId in devicesCountById) {
+            if (! deletedWallsUids.includes(structureId)) {
+                let wall: Nub;
+                if (this.model.downWall.uid === structureId) {
+                    wall = this.model.downWall;
+                } else {
+                    wall = this.model.getChild(structureId);
+                }
+                if (wall.getChildren().length <= devicesCountById[structureId]) {
+                    tooFewDevices = true;
+                }
+            }
+        }
+
         return (
-            this.selectedItems.length === 1
-            && ! (this.selectedItem instanceof CloisonAval) // exclude downwall
-            && this.selectedItem.parent
-            && this.selectedItem.parent.getChildren().length > 1
+            this.selectedItems.length > 0
+            && wallsCount < this.model.children.length // at least one basin must remain
+            && ! containsDownwall
+            && ! containsOrphanNub
+            && ! tooFewDevices
         );
     }
 
@@ -1040,15 +1081,44 @@ export class PabTableComponent implements AfterViewInit, OnInit {
     }
 
     public onRemoveClick() {
-        const pos = this.selectedItem.findPositionInParent() + 1;
-        this.selectedItem.parent.deleteChild(this.selectedItem.findPositionInParent());
-        if (this.selectedItem instanceof Structure) {
-            this.notifService.notify(sprintf(this.i18nService.localizeText("INFO_DEVICE_REMOVED"), pos));
-        } else {
-            this.notifService.notify(sprintf(this.i18nService.localizeText("INFO_WALL_REMOVED"), pos));
+        let wallsCount = 0;
+        let devicesCount = 0;
+        const deletedWallsUids = [];
+
+        // first pass: gather deleted structures UIDs
+        for (const se of this.selectedItems) {
+            if (! (se instanceof Structure)) {
+                wallsCount++;
+                deletedWallsUids.push(se.uid);
+            }
+        }
+
+        // second pass: remove
+        for (const se of this.selectedItems) {
+            if (se instanceof Structure) { // device
+                // do not remove device if parent structure is to be removed too
+                if (! deletedWallsUids.includes(se.parent.uid)) {
+                    se.parent.deleteChild(se.findPositionInParent());
+                    devicesCount++;
+                }
+            } else {
+                // remove wall
+                se.parent.deleteChild(se.findPositionInParent());
+            }
         }
         this.selectedItems = [];
         this.refresh();
+
+        // notify
+        let msg: string;
+        if (wallsCount === 0) {
+            msg = sprintf(this.i18nService.localizeText("INFO_DEVICES_REMOVED"), devicesCount);
+        } else if (devicesCount === 0) {
+            msg = sprintf(this.i18nService.localizeText("INFO_WALLS_REMOVED"), wallsCount);
+        } else {
+            msg = sprintf(this.i18nService.localizeText("INFO_WALLS_AND_DEVICES_REMOVED"), wallsCount, devicesCount);
+        }
+        this.notifService.notify(msg);
     }
 
     public get uitextAdd(): string {
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 5e8589a68068344dd63aa3075f97d2cd4501ec38..c107256cbfd39792eba921b46a626fec44fcb58b 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -122,6 +122,7 @@
     "INFO_DEVICE_COPIED_N_TIMES": "Device #%s copied %s times",
     "INFO_DEVICE_MOVED": "Device #%s moved",
     "INFO_DEVICE_REMOVED": "Device #%s removed",
+    "INFO_DEVICES_REMOVED": "%s device(s) removed",
     "INFO_FIELDSET_ADD": "Add",
     "INFO_FIELDSET_COPY": "Copy",
     "INFO_FIELDSET_REMOVE": "Remove",
@@ -135,6 +136,8 @@
     "INFO_WALL_COPIED_N_TIMES": "Wall #%s copied %s times",
     "INFO_WALL_MOVED": "Wall #%s moved",
     "INFO_WALL_REMOVED": "Wall #%s removed",
+    "INFO_WALLS_AND_DEVICES_REMOVED": "%s wall(s) and %s device(s) removed",
+    "INFO_WALLS_REMOVED": "%s wall(s) removed",
     "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
     "INFO_LIB_LENGTHS": "Every length",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index c28d769f082518f610c87a933f6b55c3361be5b9..478772b1b2adb3016778d987eadedc9793d8c7f5 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -122,6 +122,7 @@
     "INFO_DEVICE_COPIED_N_TIMES": "Ouvrage n°%s copié %s fois",
     "INFO_DEVICE_MOVED": "Ouvrage n°%s déplacé",
     "INFO_DEVICE_REMOVED": "Ouvrage n°%s supprimé",
+    "INFO_DEVICES_REMOVED": "%s ouvrage(s) supprimé(s)",
     "INFO_FIELDSET_ADD": "Ajouter",
     "INFO_FIELDSET_COPY": "Copier",
     "INFO_FIELDSET_REMOVE": "Supprimer",
@@ -135,6 +136,8 @@
     "INFO_WALL_COPIED_N_TIMES": "Cloison n°%s copiée %s fois",
     "INFO_WALL_MOVED": "Cloison n°%s déplacée",
     "INFO_WALL_REMOVED": "Cloison n°%s supprimée",
+    "INFO_WALLS_AND_DEVICES_REMOVED": "%s cloison(s) et %s ouvrage(s) supprimé(s)",
+    "INFO_WALLS_REMOVED": "%s cloison(s) supprimée(s)",
     "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
     "INFO_LIB_LENGTHS": "Toutes les longueurs",