diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-35245-ReworkWorkspaceNotificationSettings.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-35245-ReworkWorkspaceNotificationSettings.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6d44b39c2627f4bb572eda8da4c46d9779c40274
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-35245-ReworkWorkspaceNotificationSettings.rst
@@ -0,0 +1,51 @@
+========================================================
+Feature: #35245 - Rework workspace notification settings
+========================================================
+
+Description
+===========
+
+The current notification settings have some drawbacks and are not easy to
+understand if it comes the the expected behavior in the workspace module.
+The settings are defined in each sys_workspace and sys_workspace_stage
+record and are evaluated in the workspace module if sending a particular
+element to be reviewed to the previous or next stage.
+
+Currently there are the following notification settings:
+* on stages
+  * "edit stage": takes recipients from "adminusers" field
+     (workspace owners)
+  * "ready to publish" stage: takes recipients from "members" field
+     (workspace members)
+* on preselection of recipients
+  * "all (non-strict)": if users from workspace setting (field "adminusers"
+    or "members") are also in the specific "default_users" setting for the
+    stage, the checkbox is enabled by default and cannot be changed,
+    otherwise it's not checked
+  * "all (strict)": all users from workspace setting (field "adminusers"
+    or "members") are checked and cannot be changed
+  * "some (strict)": all users from workspace setting (field "adminusers"
+     or "members") are checked, but still can be changed
+* behavior
+  * sending to "edit" stage: members are notified per default
+  * sending to "ready to publish" stage: owners are notified per default
+
+The changes extends the possibilities to define notification settings:
+* on stages
+  * add settings for "publish-execute" stage (actual publishing process)
+* on preselection of recipients
+  * remove modes
+  * replace settings for showing the dialog and whether modifying the
+    preselection is allowed at all (getting rid of the "strict" modes)
+  * add possibilities to defined notification recipients
+    * owner & members as defined in the accordant fields
+    * editors that have been working on a particular element
+    * responsible persons (on custom stages only)
+
+Impact
+======
+
+The meaning and behavior of the workspaces notification settings concerning
+preselected recipients and the possibility to modify the selection on moving
+an element to a particular change is different now. However, an upgrade wizard
+helps to upgrade the settings to the new definitions.
\ No newline at end of file
diff --git a/typo3/sysext/install/Classes/Updates/WorkspacesNotificationSettingsUpdate.php b/typo3/sysext/install/Classes/Updates/WorkspacesNotificationSettingsUpdate.php
new file mode 100644
index 0000000000000000000000000000000000000000..d79f781cf53af86e495e185b702dba918e8ce037
--- /dev/null
+++ b/typo3/sysext/install/Classes/Updates/WorkspacesNotificationSettingsUpdate.php
@@ -0,0 +1,177 @@
+<?php
+namespace TYPO3\CMS\Install\Updates;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+
+/**
+ * Migrate the workspaces notification settings to the enhanced schema.
+ */
+class WorkspacesNotificationSettingsUpdate extends AbstractUpdate {
+
+	/**
+	 * @var string
+	 */
+	protected $title = 'Migrate the workspaces notification settings to the enhanced schema';
+
+	/**
+	 * Checks if an update is needed
+	 *
+	 * @param string &$description The description for the update
+	 * @return bool Whether an update is needed (TRUE) or not (FALSE)
+	 */
+	public function checkForUpdate(&$description) {
+		if (!ExtensionManagementUtility::isLoaded('workspaces')) {
+			return FALSE;
+		}
+
+		if ($this->isWizardDone()) {
+			return FALSE;
+		}
+
+		$workspacesCount = $this->getDatabaseConnection()->exec_SELECTcountRows(
+			'uid',
+			'sys_workspace',
+			'deleted=0'
+		);
+
+		$stagesCount = $this->getDatabaseConnection()->exec_SELECTcountRows(
+			'uid',
+			'sys_workspace_stage',
+			'deleted=0'
+		);
+
+		if ($workspacesCount + $stagesCount > 0) {
+			$description = 'The workspaces notification settings have been extended'
+				. ' and need to be migrated to the new definitions. This update wizard'
+				. ' upgrades the accordant settings in the availble workspaces and stages.';
+			return TRUE;
+		} else {
+			$this->markWizardAsDone();
+		}
+
+		return FALSE;
+	}
+
+	/**
+	 * Perform the database updates for workspace records
+	 *
+	 * @param array &$databaseQueries Queries done in this update
+	 * @param mixed &$customMessages Custom messages
+	 * @return bool
+	 */
+	public function performUpdate(array &$databaseQueries, &$customMessages) {
+		$databaseConnection = $this->getDatabaseConnection();
+
+		$workspaceRecords = $databaseConnection->exec_SELECTgetRows('*', 'sys_workspace', 'deleted=0');
+		foreach ($workspaceRecords as $workspaceRecord) {
+			$update = $this->prepareWorkspaceUpdate($workspaceRecord);
+			if ($update !== NULL) {
+				$databaseConnection->exec_UPDATEquery('sys_workspace', 'uid=' . (int)$workspaceRecord['uid'], $update);
+				$databaseQueries[] = $databaseConnection->debug_lastBuiltQuery;
+			}
+		}
+
+		$stageRecords = $databaseConnection->exec_SELECTgetRows('*', 'sys_workspace_stage', 'deleted=0');
+		foreach ($stageRecords as $stageRecord) {
+			$update = $this->prepareStageUpdate($stageRecord);
+			if ($update !== NULL) {
+				$databaseConnection->exec_UPDATEquery('sys_workspace_stage', 'uid=' . (int)$stageRecord['uid'], $update);
+				$databaseQueries[] = $databaseConnection->debug_lastBuiltQuery;
+			}
+		}
+
+		$this->markWizardAsDone();
+		return TRUE;
+	}
+
+	/**
+	 * Prepares SQL updates for workspace records.
+	 *
+	 * @param array $workspaceRecord
+	 * @return array|NULL
+	 */
+	protected function prepareWorkspaceUpdate(array $workspaceRecord) {
+		if (empty($workspaceRecord['uid'])) {
+			return NULL;
+		}
+
+		$update = array();
+		$update = $this->mapSettings($workspaceRecord, $update, 'edit', 'edit');
+		$update = $this->mapSettings($workspaceRecord, $update, 'publish', 'publish');
+		$update = $this->mapSettings($workspaceRecord, $update, 'publish', 'execute');
+		return $update;
+	}
+
+	/**
+	 * Prepares SQL update for stage records.
+	 *
+	 * @param array $stageRecord
+	 * @return array|null
+	 */
+	protected function prepareStageUpdate(array $stageRecord) {
+		if (empty($stageRecord['uid'])) {
+			return NULL;
+		}
+
+		$update = array();
+		$update = $this->mapSettings($stageRecord, $update);
+		return $update;
+	}
+
+	/**
+	 * Maps settings to new meaning.
+	 *
+	 * @param array $record
+	 * @param array $update
+	 * @param string $from
+	 * @param string $to
+	 * @return array
+	 */
+	protected function mapSettings(array $record, array $update, $from = '', $to = '') {
+		$fromPrefix = ($from ? $from . '_' : '');
+		$toPrefix = ($to ? $to . '_' : '');
+
+		$settings = 0;
+		// Previous setting: "Allow notification settings during stage change"
+		if ($record[$fromPrefix . 'allow_notificaton_settings']) {
+			$settings += 1;
+		}
+		// Previous setting: "All are selected per default (can be changed)"
+		if ((int)$record[$fromPrefix . 'notification_mode'] === 0) {
+			$settings += 2;
+		}
+
+		// Custom stages: preselect responsible persons (8)
+		if (isset($record['responsible_persons'])) {
+			$preselection = 8;
+		// Workspace "edit" stage: preselect members (2)
+		} elseif ($to === 'edit') {
+			$preselection = 2;
+		// Workspace "publish" stage: preselect owners (1)
+		} elseif ($to === 'publish') {
+			$preselection = 1;
+		// Workspace "execute" stage: preselect owners (1) and members (2) as default
+		} else {
+			$preselection = 1 + 2;
+		}
+
+		$update[$toPrefix . 'allow_notificaton_settings'] = $settings;
+		$update[$toPrefix . 'notification_preselection'] = $preselection;
+
+		return $update;
+	}
+
+}
diff --git a/typo3/sysext/install/ext_localconf.php b/typo3/sysext/install/ext_localconf.php
index 157a657db723830c246ac2696d5f46054e70504e..dfc33610866cd663f37ff20d16c19b0168d7c03d 100644
--- a/typo3/sysext/install/ext_localconf.php
+++ b/typo3/sysext/install/ext_localconf.php
@@ -11,6 +11,7 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['filesReplace
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['tableCType'] = \TYPO3\CMS\Install\Updates\TableFlexFormToTtContentFieldsUpdate::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\TYPO3\CMS\Install\Updates\FileListIsStartModuleUpdate::class] = \TYPO3\CMS\Install\Updates\FileListIsStartModuleUpdate::class;
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['textmediaCType'] = \TYPO3\CMS\Install\Updates\ContentTypesToTextMediaUpdate::class;
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\TYPO3\CMS\Install\Updates\WorkspacesNotificationSettingsUpdate::class] = \TYPO3\CMS\Install\Updates\WorkspacesNotificationSettingsUpdate::class;
 
 $signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
 $signalSlotDispatcher->connect(
diff --git a/typo3/sysext/workspaces/Classes/Domain/Model/DatabaseRecord.php b/typo3/sysext/workspaces/Classes/Domain/Model/DatabaseRecord.php
index 142b6e9e1d6d7eb752710d88af9bd62103cb6526..372ebc9fac3a2a5ffc410861c1a9ce13cd694a36 100644
--- a/typo3/sysext/workspaces/Classes/Domain/Model/DatabaseRecord.php
+++ b/typo3/sysext/workspaces/Classes/Domain/Model/DatabaseRecord.php
@@ -104,7 +104,7 @@ class DatabaseRecord {
 	 * @return void
 	 */
 	public function setUid($uid) {
-		$this->uid = $uid;
+		$this->uid = (int)$uid;
 	}
 
 	/**
diff --git a/typo3/sysext/workspaces/Classes/Domain/Record/AbstractRecord.php b/typo3/sysext/workspaces/Classes/Domain/Record/AbstractRecord.php
new file mode 100644
index 0000000000000000000000000000000000000000..7768aae57cc7576576145d15dc5b4345569f1a62
--- /dev/null
+++ b/typo3/sysext/workspaces/Classes/Domain/Record/AbstractRecord.php
@@ -0,0 +1,94 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Domain\Record;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Workspaces\Service\StagesService;
+
+/**
+ * Combined record class
+ */
+abstract class AbstractRecord {
+
+	/**
+	 * @var array
+	 */
+	protected $record;
+
+	static protected function fetch($tableName, $uid) {
+		$record = static::getDatabaseConnection()->exec_SELECTgetSingleRow('*', $tableName, 'deleted=0 AND uid=' . (int)$uid);
+		if (empty($record)) {
+			throw new \RuntimeException('Record "' . $tableName . ':' . $uid . '" not found');
+		}
+		return $record;
+	}
+
+	/**
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	static protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
+	/**
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+	 */
+	static protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
+	}
+
+	/**
+	 * @return \TYPO3\CMS\Lang\LanguageService
+	 */
+	static protected function getLanguageService() {
+		return $GLOBALS['LANG'];
+	}
+
+	/**
+	 * @param array $record
+	 */
+	public function __construct(array $record) {
+		$this->record = $record;
+	}
+
+	/**
+	 * @return string
+	 */
+	public function __toString() {
+		return (string)$this->getUid();
+	}
+
+	/**
+	 * @return int
+	 */
+	public function getUid() {
+		return (int)$this->record['uid'];
+	}
+
+	/**
+	 * @return string
+	 */
+	public function getTitle() {
+		return (string)$this->record['title'];
+	}
+
+	/**
+	 * @return StagesService
+	 */
+	protected function getStagesService() {
+		return GeneralUtility::makeInstance(StagesService::class);
+	}
+
+}
diff --git a/typo3/sysext/workspaces/Classes/Domain/Record/StageRecord.php b/typo3/sysext/workspaces/Classes/Domain/Record/StageRecord.php
new file mode 100644
index 0000000000000000000000000000000000000000..b198cbad8e4f44dde67847d9685361a52a449b51
--- /dev/null
+++ b/typo3/sysext/workspaces/Classes/Domain/Record/StageRecord.php
@@ -0,0 +1,340 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Domain\Record;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Workspaces\Service\StagesService;
+
+/**
+ * Combined record class
+ */
+class StageRecord extends AbstractRecord{
+
+	/**
+	 * @var WorkspaceRecord
+	 */
+	protected $workspace;
+
+	/**
+	 * @var bool
+	 */
+	protected $internal = FALSE;
+
+	/**
+	 * @var array
+	 */
+	protected $responsiblePersons;
+
+	/**
+	 * @var array
+	 */
+	protected $defaultRecipients;
+
+	/**
+	 * @var array
+	 */
+	protected $preselectedRecipients;
+
+	/**
+	 * @var array
+	 */
+	protected $allRecipients;
+
+	/**
+	 * @param int $uid
+	 * @param array $record
+	 * @return StageRecord
+	 */
+	static public function get($uid, array $record = NULL) {
+		if (empty($record)) {
+			$record = static::fetch('sys_workspace_stage', $uid);
+		}
+		return WorkspaceRecord::get($record['parentid'])->getStage($uid);
+	}
+
+	/**
+	 * @param WorkspaceRecord $workspace
+	 * @param int $uid
+	 * @param array $record
+	 * @return StageRecord
+	 */
+	static public function build(WorkspaceRecord $workspace, $uid, array $record = NULL) {
+		if (empty($record)) {
+			$record = static::fetch('sys_workspace_stage', $uid);
+		}
+		return new StageRecord($workspace, $record);
+	}
+
+	/**
+	 * @param WorkspaceRecord $workspace
+	 * @param array $record
+	 */
+	public function __construct(WorkspaceRecord $workspace, array $record) {
+		parent::__construct($record);
+		$this->workspace = $workspace;
+	}
+
+	/**
+	 * @return WorkspaceRecord
+	 */
+	public function getWorkspace() {
+		return $this->workspace;
+	}
+
+	/**
+	 * @return NULL|StageRecord
+	 */
+	public function getPrevious() {
+		return $this->getWorkspace()->getPreviousStage($this->getUid());
+	}
+
+	/**
+	 * @return NULL|StageRecord
+	 */
+	public function getNext() {
+		return $this->getWorkspace()->getNextStage($this->getUid());
+	}
+
+	/**
+	 * @param StageRecord $stageRecord
+	 * @return int
+	 */
+	public function determineOrder(StageRecord $stageRecord) {
+		if ($this->getUid() === $stageRecord->getUid()) {
+			return 0;
+		} elseif ($this->isEditStage() || $stageRecord->isExecuteStage() || $this->isPreviousTo($stageRecord)) {
+			return -1;
+		} elseif ($this->isExecuteStage() || $stageRecord->isEditStage() || $this->isNextTo($stageRecord)) {
+			return 1;
+		}
+		return 0;
+	}
+
+	/**
+	 * Determines whether $this is in a previous stage compared to $stageRecord.
+	 *
+	 * @param StageRecord $stageRecord
+	 * @return bool
+	 */
+	public function isPreviousTo(StageRecord $stageRecord) {
+		$current = $stageRecord;
+		while ($previous = $current->getPrevious()) {
+			if ($this->getUid() === $previous->getUid()) {
+				return TRUE;
+			}
+			$current = $previous;
+		}
+		return FALSE;
+	}
+
+	/**
+	 * Determines whether $this is in a later stage compared to $stageRecord.
+	 *
+	 * @param StageRecord $stageRecord
+	 * @return bool
+	 */
+	public function isNextTo(StageRecord $stageRecord) {
+		$current = $stageRecord;
+		while ($next = $current->getNext()) {
+			if ($this->getUid() === $next->getUid()) {
+				return TRUE;
+			}
+			$current = $next;
+		}
+		return FALSE;
+	}
+
+	/**
+	 * @return string
+	 */
+	public function getDefaultComment() {
+		$defaultComment = '';
+		if (isset($this->record['default_mailcomment'])) {
+			$defaultComment = $this->record['default_mailcomment'];
+		}
+		return $defaultComment;
+	}
+
+	/**
+	 * @param bool $internal
+	 */
+	public function setInternal($internal = TRUE) {
+		$this->internal = (bool)$internal;
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isInternal() {
+		return $this->internal;
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isEditStage() {
+		return ($this->getUid() === StagesService::STAGE_EDIT_ID);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isPublishStage() {
+		return ($this->getUid() === StagesService::STAGE_PUBLISH_ID);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isExecuteStage() {
+		return ($this->getUid() === StagesService::STAGE_PUBLISH_EXECUTE_ID);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isDialogEnabled() {
+		return (((int)$this->record['allow_notificaton_settings'] & 1) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isPreselectionChangeable() {
+		return (((int)$this->record['allow_notificaton_settings'] & 2) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function areOwnersPreselected() {
+		return (((int)$this->record['notification_preselection'] & 1) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function areMembersPreselected() {
+		return (((int)$this->record['notification_preselection'] & 2) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function areEditorsPreselected() {
+		return (((int)$this->record['notification_preselection'] & 4) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function areResponsiblePersonsPreselected() {
+		return (((int)$this->record['notification_preselection'] & 8) > 0);
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function hasPreselection() {
+		return (
+			$this->areOwnersPreselected()
+			|| $this->areMembersPreselected()
+			|| $this->areEditorsPreselected()
+			|| $this->areResponsiblePersonsPreselected()
+		);
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getResponsiblePersons() {
+		if (!isset($this->responsiblePersons)) {
+			$this->responsiblePersons = array();
+			if (!empty($this->record['responsible_persons'])) {
+				$this->responsiblePersons = $this->getStagesService()->resolveBackendUserIds($this->record['responsible_persons']);
+			}
+		}
+		return $this->responsiblePersons;
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getDefaultRecipients() {
+		if (!isset($this->defaultRecipients)) {
+			$this->defaultRecipients = $this->getStagesService()->resolveBackendUserIds($this->record['notification_defaults']);
+		}
+		return $this->defaultRecipients;
+	}
+
+	/**
+	 * Gets all recipients (backend user ids).
+	 *
+	 * @return array
+	 */
+	public function getAllRecipients() {
+		if (!isset($this->allRecipients)) {
+			$allRecipients = $this->getDefaultRecipients();
+
+			if ($this->isInternal() || $this->areOwnersPreselected()) {
+				$allRecipients = array_merge($allRecipients, $this->getWorkspace()->getOwners());
+			}
+			if ($this->isInternal() || $this->areMembersPreselected()) {
+				$allRecipients = array_merge($allRecipients, $this->getWorkspace()->getMembers());
+			}
+			if (!$this->isInternal()) {
+				$allRecipients = array_merge($allRecipients, $this->getResponsiblePersons());
+			}
+
+			$this->allRecipients = array_unique($allRecipients);
+		}
+
+		return $this->allRecipients;
+	}
+
+	/**
+	 * @return int[]
+	 */
+	public function getPreselectedRecipients() {
+		if (!isset($this->preselectedRecipients)) {
+			$preselectedRecipients = $this->getDefaultRecipients();
+
+			if ($this->areOwnersPreselected()) {
+				$preselectedRecipients = array_merge($preselectedRecipients, $this->getWorkspace()->getOwners());
+			}
+			if ($this->areMembersPreselected()) {
+				$preselectedRecipients = array_merge($preselectedRecipients, $this->getWorkspace()->getMembers());
+			}
+			if ($this->areResponsiblePersonsPreselected()) {
+				$preselectedRecipients = array_merge($preselectedRecipients, $this->getResponsiblePersons());
+			}
+
+			$this->preselectedRecipients = array_unique($preselectedRecipients);
+		}
+
+		return $this->preselectedRecipients;
+	}
+
+	/**
+	 * @return bool
+	 */
+	public function isAllowed() {
+		return (
+			$this->isEditStage()
+			|| static::getBackendUser()->workspaceCheckStageForCurrent($this->getUid())
+			|| $this->isExecuteStage() && static::getBackendUser()->workspacePublishAccess($this->workspace->getUid())
+		);
+	}
+
+}
diff --git a/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php b/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
new file mode 100644
index 0000000000000000000000000000000000000000..b951776cb48314ed0d34c15503fa43fd920ec5f1
--- /dev/null
+++ b/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
@@ -0,0 +1,209 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Domain\Record;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Workspaces\Service\StagesService;
+
+/**
+ * Combined record class
+ */
+class WorkspaceRecord extends AbstractRecord{
+
+	/**
+	 * @var array
+	 */
+	protected $internalStages = array(
+		StagesService::STAGE_EDIT_ID => array(
+			'name' => 'edit',
+			'label' => 'LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_editing'
+		),
+		StagesService::STAGE_PUBLISH_ID => array(
+			'name' => 'publish',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_ready_to_publish'
+		),
+		StagesService::STAGE_PUBLISH_EXECUTE_ID => array(
+			'name' => 'execute',
+			'label' => 'LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_publish'
+		),
+	);
+
+	/**
+	 * @var array
+	 */
+	protected $internalStageFieldNames = array(
+		'notification_defaults',
+		'notification_preselection',
+		'allow_notificaton_settings'
+	);
+
+	/**
+	 * @var array
+	 */
+	protected $owners;
+
+	/**
+	 * @var array
+	 */
+	protected $members;
+
+	/**
+	 * @var StageRecord[]
+	 */
+	protected $stages;
+
+	/**
+	 * @param int $uid
+	 * @param array $record
+	 * @return WorkspaceRecord
+	 */
+	static public function get($uid, array $record = NULL) {
+		if (empty($uid)) {
+			$record = array();
+		} elseif (empty($record)) {
+			$record = static::fetch('sys_workspace', $uid);
+		}
+		return new static($record);
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getOwners() {
+		if (!isset($this->owners)) {
+			$this->owners = $this->getStagesService()->resolveBackendUserIds($this->record['adminusers']);
+		}
+		return $this->owners;
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getMembers() {
+		if (!isset($this->members)) {
+			$this->members = $this->getStagesService()->resolveBackendUserIds($this->record['members']);
+		}
+		return $this->members;
+	}
+
+	/**
+	 * @return StageRecord[]
+	 */
+	public function getStages() {
+		if (!isset($this->stages)) {
+			$this->stages = array();
+			$this->addStage($this->createInternalStage(StagesService::STAGE_EDIT_ID));
+
+			$records = self::getDatabaseConnection()->exec_SELECTgetRows(
+				'*', 'sys_workspace_stage',
+				'deleted=0 AND parentid=' . $this->getUid() . ' AND parenttable='
+					. self::getDatabaseConnection()->fullQuoteStr('sys_workspace', 'sys_workspace_stage'),
+				'', 'sorting'
+			);
+			if (!empty($records)) {
+				foreach ($records as $record) {
+					$this->addStage(StageRecord::build($this, $record['uid'], $record));
+				}
+			}
+
+			$this->addStage($this->createInternalStage(StagesService::STAGE_PUBLISH_ID));
+			$this->addStage($this->createInternalStage(StagesService::STAGE_PUBLISH_EXECUTE_ID));
+		}
+
+		return $this->stages;
+	}
+
+	/**
+	 * @param int $stageId
+	 * @return NULL|StageRecord
+	 */
+	public function getStage($stageId) {
+		$stageId = (int)$stageId;
+		$this->getStages();
+		if (!isset($this->stages[$stageId])) {
+			return NULL;
+		}
+		return $this->stages[$stageId];
+	}
+
+	/**
+	 * @param int $stageId
+	 * @return NULL|StageRecord
+	 */
+	public function getPreviousStage($stageId) {
+		$stageId = (int)$stageId;
+		$stageIds = array_keys($this->getStages());
+		$stageIndex = array_search($stageId, $stageIds);
+
+		// catches "0" (edit stage) as well
+		if (empty($stageIndex)) {
+			return NULL;
+		}
+
+		$previousStageId = $stageIds[$stageIndex - 1];
+		return $this->stages[$previousStageId];
+	}
+
+	/**
+	 * @param int $stageId
+	 * @return NULL|StageRecord
+	 */
+	public function getNextStage($stageId) {
+		$stageId = (int)$stageId;
+		$stageIds = array_keys($this->getStages());
+		$stageIndex = array_search($stageId, $stageIds);
+
+		if ($stageIndex === FALSE || !isset($stageIds[$stageIndex + 1])) {
+			return NULL;
+		}
+
+		$nextStageId = $stageIds[$stageIndex + 1];
+		return $this->stages[$nextStageId];
+	}
+
+	/**
+	 * @param StageRecord $stage
+	 */
+	protected function addStage(StageRecord $stage) {
+		$this->stages[$stage->getUid()] = $stage;
+	}
+
+	/**
+	 * @param int $stageId
+	 * @return StageRecord
+	 * @throws \RuntimeException
+	 */
+	protected function createInternalStage($stageId) {
+		$stageId = (int)$stageId;
+
+		if (!isset($this->internalStages[$stageId])) {
+			throw new \RuntimeException('Invalid internal stage "' . $stageId . '"');
+		}
+
+		$record = array(
+			'uid' => $stageId,
+			'title' => static::getLanguageService()->sL($this->internalStages[$stageId]['label'])
+		);
+
+		$fieldNamePrefix = $this->internalStages[$stageId]['name'] . '_';
+		foreach ($this->internalStageFieldNames as $fieldName) {
+			$record[$fieldName] = $this->record[$fieldNamePrefix . $fieldName];
+		}
+
+		$stage = StageRecord::build($this, $stageId, $record);
+		$stage->setInternal(TRUE);
+		return $stage;
+	}
+
+}
diff --git a/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php b/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
index 526812c32513b84d7951eb20b0e3f51d124fefda..bf7e6730896e28b25b1500ea847c980ce774386f 100644
--- a/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
+++ b/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
@@ -17,6 +17,8 @@ namespace TYPO3\CMS\Workspaces\ExtDirect;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Workspaces\Service\StagesService;
+use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
+use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
 
 /**
  * ExtDirect action handler
@@ -224,13 +226,14 @@ class ActionHandler extends AbstractHandler {
 		$currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
 
 		if (is_array($elementRecord)) {
-			$stageId = $elementRecord['t3ver_stage'];
-			if ($this->getStageService()->isValid($stageId)) {
-				$nextStage = $this->getStageService()->getNextStage($stageId);
-				$result = $this->getSentToStageWindow($nextStage['uid']);
+			$workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
+			$nextStageRecord = $workspaceRecord->getNextStage($elementRecord['t3ver_stage']);
+			if ($nextStageRecord !== NULL) {
+				$this->stageService->getRecordService()->add($table, $uid);
+				$result = $this->getSentToStageWindow($nextStageRecord);
 				$result['affects'] = array(
 					'table' => $table,
-					'nextStage' => $nextStage['uid'],
+					'nextStage' => $nextStageRecord->getUid(),
 					't3ver_oid' => $t3ver_oid,
 					'uid' => $uid
 				);
@@ -257,15 +260,18 @@ class ActionHandler extends AbstractHandler {
 		$currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
 
 		if (is_array($elementRecord)) {
-			$stageId = $elementRecord['t3ver_stage'];
-			if ($this->getStageService()->isValid($stageId)) {
-				if ($stageId !== StagesService::STAGE_EDIT_ID) {
-					$prevStage = $this->getStageService()->getPrevStage($stageId);
-					$result = $this->getSentToStageWindow($prevStage['uid']);
+			$workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
+			$stageRecord = $workspaceRecord->getStage($elementRecord['t3ver_stage']);
+
+			if ($stageRecord !== NULL) {
+				if (!$stageRecord->isEditStage()) {
+					$this->stageService->getRecordService()->add($table, $uid);
+					$previousStageRecord = $stageRecord->getPrevious();
+					$result = $this->getSentToStageWindow($previousStageRecord);
 					$result['affects'] = array(
 						'table' => $table,
 						'uid' => $uid,
-						'nextStage' => $prevStage['uid']
+						'nextStage' => $previousStageRecord->getUid()
 					);
 				} else {
 					// element is already in edit stage, there is no prev stage - return an error message
@@ -286,9 +292,17 @@ class ActionHandler extends AbstractHandler {
 	 * Gets the dialog window to be displayed before a record can be sent to a specific stage.
 	 *
 	 * @param int $nextStageId
+	 * @param array|\stdClass[] $elements
 	 * @return array
 	 */
-	public function sendToSpecificStageWindow($nextStageId) {
+	public function sendToSpecificStageWindow($nextStageId, array $elements) {
+		foreach ($elements as $element) {
+			$this->stageService->getRecordService()->add(
+				$element->table,
+				$element->uid
+			);
+		}
+
 		$result = $this->getSentToStageWindow($nextStageId);
 		$result['affects'] = array(
 			'nextStage' => $nextStageId
@@ -299,20 +313,27 @@ class ActionHandler extends AbstractHandler {
 	/**
 	 * Gets a merged variant of recipient defined by uid and custom ones.
 	 *
-	 * @param array list of recipients
-	 * @param string given user string of additional recipients
-	 * @param int stage id
+	 * @param array $uidOfRecipients list of recipients
+	 * @param string $additionalRecipients given user string of additional recipients
+	 * @param int $stageId stage id
 	 * @return array
+	 * @throws \InvalidArgumentException
 	 */
 	public function getRecipientList(array $uidOfRecipients, $additionalRecipients, $stageId) {
-		$finalRecipients = array();
-		if (!$this->getStageService()->isValid($stageId)) {
+		$stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageId);
+
+		if ($stageRecord === NULL) {
 			throw new \InvalidArgumentException($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'));
-		} else {
-			$stageId = (int)$stageId;
 		}
+
 		$recipients = array();
+		$finalRecipients = array();
+		$backendUserIds = $stageRecord->getAllRecipients();
 		foreach ($uidOfRecipients as $userUid) {
+			// Ensure that only configured backend users are considered
+			if (!in_array($userUid, $backendUserIds)) {
+				continue;
+			}
 			$beUserRecord = BackendUtility::getRecord('be_users', (int)$userUid);
 			if (is_array($beUserRecord) && $beUserRecord['email'] !== '') {
 				$uc = $beUserRecord['uc'] ? unserialize($beUserRecord['uc']) : array();
@@ -322,22 +343,26 @@ class ActionHandler extends AbstractHandler {
 				);
 			}
 		}
-		// the notification mode can be configured in the workspace stage record
-		$notification_mode = (int)$this->getStageService()->getNotificationMode($stageId);
-		if ($notification_mode === StagesService::MODE_NOTIFY_ALL || $notification_mode === StagesService::MODE_NOTIFY_ALL_STRICT) {
-			// get the default recipients from the stage configuration
-			// the default recipients needs to be added in some cases of the notification_mode
-			$default_recipients = $this->getStageService()->getResponsibleBeUser($stageId, TRUE);
-			foreach ($default_recipients as $default_recipient_uid => $default_recipient_record) {
-				if (!isset($recipients[$default_recipient_record['email']])) {
-					$uc = $default_recipient_record['uc'] ? unserialize($default_recipient_record['uc']) : array();
-					$recipients[$default_recipient_record['email']] = array(
-						'email' => $default_recipient_record['email'],
-						'lang' => isset($uc['lang']) ? $uc['lang'] : $default_recipient_record['lang']
+
+		if ($stageRecord->hasPreselection() && !$stageRecord->isPreselectionChangeable()) {
+			$preselectedBackendUsers = $this->getStageService()->getBackendUsers(
+				implode(',', $this->stageService->getPreselectedRecipients($stageRecord))
+			);
+
+			foreach ($preselectedBackendUsers as $preselectedBackendUser) {
+				if (empty($preselectedBackendUser['email']) || !GeneralUtility::validEmail($preselectedBackendUser['email'])) {
+					continue;
+				}
+				if (!isset($recipients[$preselectedBackendUser['email']])) {
+					$uc = (!empty($preselectedBackendUser['uc']) ? unserialize($preselectedBackendUser['uc']) : array());
+					$recipients[$preselectedBackendUser['email']] = array(
+						'email' => $preselectedBackendUser['email'],
+						'lang' => (isset($uc['lang']) ? $uc['lang'] : $preselectedBackendUser['lang'])
 					);
 				}
 			}
 		}
+
 		if ($additionalRecipients !== '') {
 			$emails = GeneralUtility::trimExplode(LF, $additionalRecipients, TRUE);
 			$additionalRecipients = array();
@@ -601,43 +626,26 @@ class ActionHandler extends AbstractHandler {
 	/**
 	 * Gets the dialog window to be displayed before a record can be sent to a stage.
 	 *
-	 * @param $nextStageId
+	 * @param StageRecord|int $nextStageId
 	 * @return array
 	 */
-	protected function getSentToStageWindow($nextStageId) {
-		$workspaceRec = BackendUtility::getRecord('sys_workspace', $this->getStageService()->getWorkspaceId());
-		$showNotificationFields = FALSE;
-		$stageTitle = $this->getStageService()->getStageTitle($nextStageId);
+	protected function getSentToStageWindow($nextStage) {
+		if (!$nextStage instanceof StageRecord) {
+			$nextStage = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($nextStage);
+		}
+
 		$result = array(
 			'title' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:actionSendToStage'),
 			'items' => array(
 				array(
 					'xtype' => 'panel',
 					'bodyStyle' => 'margin-bottom: 7px; border: none;',
-					'html' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.itemsWillBeSentTo') . ' ' . $stageTitle
+					'html' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.itemsWillBeSentTo') . ' ' . $nextStage->getTitle()
 				)
 			)
 		);
-		switch ($nextStageId) {
-			case StagesService::STAGE_PUBLISH_EXECUTE_ID:
 
-			case StagesService::STAGE_PUBLISH_ID:
-				if (!empty($workspaceRec['publish_allow_notificaton_settings'])) {
-					$showNotificationFields = TRUE;
-				}
-				break;
-			case StagesService::STAGE_EDIT_ID:
-				if (!empty($workspaceRec['edit_allow_notificaton_settings'])) {
-					$showNotificationFields = TRUE;
-				}
-				break;
-			default:
-				$allow_notificaton_settings = $this->getStageService()->getPropertyOfCurrentWorkspaceStage($nextStageId, 'allow_notificaton_settings');
-				if (!empty($allow_notificaton_settings)) {
-					$showNotificationFields = TRUE;
-				}
-		}
-		if ($showNotificationFields == TRUE) {
+		if ($nextStage->isDialogEnabled()) {
 			$result['items'][] = array(
 				'fieldLabel' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.sendMailTo'),
 				'xtype' => 'checkboxgroup',
@@ -646,7 +654,7 @@ class ActionHandler extends AbstractHandler {
 				'style' => 'max-height: 200px',
 				'autoScroll' => TRUE,
 				'items' => array(
-					$this->getReceipientsOfStage($nextStageId)
+					$this->getReceipientsOfStage($nextStage->getUid())
 				)
 			);
 			$result['items'][] = array(
@@ -661,52 +669,45 @@ class ActionHandler extends AbstractHandler {
 			'name' => 'comments',
 			'xtype' => 'textarea',
 			'width' => 250,
-			'value' => $this->getDefaultCommentOfStage($nextStageId)
+			'value' => ($nextStage->isInternal() ? '' : $nextStage->getDefaultComment())
 		);
+
 		return $result;
 	}
 
 	/**
 	 * Gets all assigned recipients of a particular stage.
 	 *
-	 * @param int $stage
+	 * @param StageRecord|int $stageRecord
 	 * @return array
 	 */
-	protected function getReceipientsOfStage($stage) {
+	protected function getReceipientsOfStage($stageRecord) {
+		if (!$stageRecord instanceof StageRecord) {
+			$stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageRecord);
+		}
+
 		$result = array();
-		$recipients = $this->getStageService()->getResponsibleBeUser($stage);
-		$default_recipients = $this->getStageService()->getResponsibleBeUser($stage, TRUE);
-		foreach ($recipients as $id => $user) {
-			if (GeneralUtility::validEmail($user['email'])) {
-				$checked = FALSE;
-				$disabled = FALSE;
-				$name = $user['realName'] ? $user['realName'] : $user['username'];
-				// the notification mode can be configured in the workspace stage record
-				$notification_mode = (int)$this->getStageService()->getNotificationMode($stage);
-				if ($notification_mode === StagesService::MODE_NOTIFY_SOMEONE) {
-					// all responsible users are checked per default, as in versions before
-					$checked = TRUE;
-				} elseif ($notification_mode === StagesService::MODE_NOTIFY_ALL) {
-					// the default users are checked only
-					if (!empty($default_recipients[$id])) {
-						$checked = TRUE;
-						$disabled = TRUE;
-					} else {
-						$checked = FALSE;
-					}
-				} elseif ($notification_mode === StagesService::MODE_NOTIFY_ALL_STRICT) {
-					// all responsible users are checked
-					$checked = TRUE;
-					$disabled = TRUE;
-				}
-				$result[] = array(
-					'boxLabel' => sprintf('%s (%s)', $name, $user['email']),
-					'name' => 'receipients-' . $id,
-					'checked' => $checked,
-					'disabled' => $disabled
-				);
+		$allRecipients = $this->getStageService()->getResponsibleBeUser($stageRecord);
+		$preselectedRecipients = $this->stageService->getPreselectedRecipients($stageRecord);
+		$isPreselectionChangeable = $stageRecord->isPreselectionChangeable();
+
+		foreach ($allRecipients as $backendUserId => $backendUser) {
+			if (empty($backendUser['email']) || !GeneralUtility::validEmail($backendUser['email'])) {
+				continue;
 			}
+
+			$name = (!empty($backendUser['realName']) ? $backendUser['realName'] : $backendUser['username']);
+			$checked = in_array($backendUserId, $preselectedRecipients);
+			$disabled = ($checked && !$isPreselectionChangeable);
+
+			$result[] = array(
+				'boxLabel' => sprintf('%s (%s)', $name, $backendUser['email']),
+				'name' => 'receipients-' . $backendUserId,
+				'checked' => $checked,
+				'disabled' => $disabled
+			);
 		}
+
 		return $result;
 	}
 
diff --git a/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php b/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
index b90617fc15c96ba29615ef34f869d40e383d455c..d50694310cab4f7ac6f2fbefe17079cbce887745 100644
--- a/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
+++ b/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
@@ -18,6 +18,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
 
 /**
  * ExtDirect server
@@ -297,4 +298,11 @@ class ExtDirectServer extends AbstractHandler {
 		return $this->stagesService;
 	}
 
+	/**
+	 * @return \TYPO3\CMS\Extbase\Object\ObjectManager
+	 */
+	protected function getObjectManager() {
+		return GeneralUtility::makeInstance(ObjectManager::class);
+	}
+
 }
diff --git a/typo3/sysext/workspaces/Classes/Service/RecordService.php b/typo3/sysext/workspaces/Classes/Service/RecordService.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7b39133939994b4a9952c3b0d007965875d93c2
--- /dev/null
+++ b/typo3/sysext/workspaces/Classes/Service/RecordService.php
@@ -0,0 +1,85 @@
+<?php
+namespace TYPO3\CMS\Workspaces\Service;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Workspaces\Domain\Model\DatabaseRecord;
+
+/**
+ * Service for records
+ */
+class RecordService implements \TYPO3\CMS\Core\SingletonInterface {
+
+	/**
+	 * @var DatabaseRecord[]
+	 */
+	protected $records = array();
+
+	/**
+	 * @param string $tableName
+	 * @param int $id
+	 */
+	public function add($tableName, $id) {
+		$databaseRecord = DatabaseRecord::create($tableName, $id);
+		if (!isset($this->records[$databaseRecord->getIdentifier()])) {
+			$this->records[$databaseRecord->getIdentifier()] = $databaseRecord;
+		}
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getIdsPerTable() {
+		$idsPerTable = array();
+		foreach ($this->records as $databaseRecord) {
+			if (!isset($idsPerTable[$databaseRecord->getTable()])) {
+				$idsPerTable[$databaseRecord->getTable()] = array();
+			}
+			$idsPerTable[$databaseRecord->getTable()][] = $databaseRecord->getUid();
+		}
+		return $idsPerTable;
+	}
+
+	/**
+	 * @return array
+	 */
+	public function getCreateUserIds() {
+		$createUserIds = array();
+		foreach ($this->getIdsPerTable() as $tableName => $ids) {
+			if (empty($GLOBALS['TCA'][$tableName]['ctrl']['cruser_id'])) {
+				continue;
+			}
+			$createUserIdFieldName = $GLOBALS['TCA'][$tableName]['ctrl']['cruser_id'];
+			$records = $this->getDatabaseConnection()->exec_SELECTgetRows(
+				$createUserIdFieldName, $tableName,
+				'uid IN (' . implode(',', $ids) . ')',
+				$createUserIdFieldName,
+				'', '',
+				$createUserIdFieldName
+			);
+			if (!empty($records)) {
+				$createUserIds = array_merge($createUserIds, array_keys($records));
+			}
+		}
+		return array_unique($createUserIds);
+	}
+
+	/**
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
+}
diff --git a/typo3/sysext/workspaces/Classes/Service/StagesService.php b/typo3/sysext/workspaces/Classes/Service/StagesService.php
index d064c19139fdf577bccddb4e642b2cbfce31b3d8..439999c4071cacff2335aa9515239f3a7e504981 100644
--- a/typo3/sysext/workspaces/Classes/Service/StagesService.php
+++ b/typo3/sysext/workspaces/Classes/Service/StagesService.php
@@ -17,11 +17,13 @@ namespace TYPO3\CMS\Workspaces\Service;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
+use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
 
 /**
  * Stages service
  */
-class StagesService {
+class StagesService implements \TYPO3\CMS\Core\SingletonInterface {
 
 	const TABLE_STAGE = 'sys_workspace_stage';
 	// if a record is in the "ready to publish" stage STAGE_PUBLISH_ID the nextStage is STAGE_PUBLISH_EXECUTE_ID, this id wont be saved at any time in db
@@ -40,6 +42,11 @@ class StagesService {
 	 */
 	private $pathToLocallang = 'LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf';
 
+	/**
+	 * @var RecordService
+	 */
+	protected $recordService;
+
 	/**
 	 * Local cache to reduce number of database queries for stages, groups, etc.
 	 *
@@ -173,35 +180,12 @@ class StagesService {
 	 * @return array id and title of the stages
 	 */
 	public function getStagesForWS() {
-		$stages = array();
 		if (isset($this->workspaceStageCache[$this->getWorkspaceId()])) {
 			$stages = $this->workspaceStageCache[$this->getWorkspaceId()];
+		} elseif ($this->getWorkspaceId() === 0) {
+			$stages = array();
 		} else {
-			$stages[] = array(
-				'uid' => self::STAGE_EDIT_ID,
-				'title' => $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "'
-					. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xlf:stage_editing') . '"'
-			);
-			$workspaceRec = BackendUtility::getRecord('sys_workspace', $this->getWorkspaceId());
-			if ($workspaceRec['custom_stages'] > 0) {
-				// Get all stage records for this workspace
-				$where = 'parentid=' . $this->getWorkspaceId() . ' AND parenttable='
-					. $GLOBALS['TYPO3_DB']->fullQuoteStr('sys_workspace', self::TABLE_STAGE) . ' AND deleted=0';
-				$workspaceStageRecs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', self::TABLE_STAGE, $where, '', 'sorting', '', 'uid');
-				foreach ($workspaceStageRecs as $stage) {
-					$stage['title'] = $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "' . $stage['title'] . '"';
-					$stages[] = $stage;
-				}
-			}
-			$stages[] = array(
-				'uid' => self::STAGE_PUBLISH_ID,
-				'title' => $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "'
-					. $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang_mod.xlf:stage_ready_to_publish') . '"'
-			);
-			$stages[] = array(
-				'uid' => self::STAGE_PUBLISH_EXECUTE_ID,
-				'title' => $GLOBALS['LANG']->sL($this->pathToLocallang . ':publish_execute_action_option')
-			);
+			$stages = $this->prepareStagesArray($this->getWorkspaceRecord()->getStages());
 			$this->workspaceStageCache[$this->getWorkspaceId()] = $stages;
 		}
 		return $stages;
@@ -213,39 +197,58 @@ class StagesService {
 	 * @return array id and title of stages
 	 */
 	public function getStagesForWSUser() {
-		$stagesForWSUserData = array();
+		if ($GLOBALS['BE_USER']->isAdmin()) {
+			return $this->getStagesForWS();
+		}
+
+		/** @var $allowedStages StageRecord[] */
 		$allowedStages = array();
-		$orderedAllowedStages = array();
-		$workspaceStageRecs = $this->getStagesForWS();
-		if (is_array($workspaceStageRecs) && !empty($workspaceStageRecs)) {
-			if ($GLOBALS['BE_USER']->isAdmin()) {
-				$orderedAllowedStages = $workspaceStageRecs;
+		$stageRecords = $this->getWorkspaceRecord()->getStages();
+
+		// Only use stages that are allowed for current backend user
+		foreach ($stageRecords as $stageRecord) {
+			if ($stageRecord->isAllowed()) {
+				$allowedStages[$stageRecord->getUid()] = $stageRecord;
+			}
+		}
+
+		// Add previous and next stages (even if they are not allowed!)
+		foreach ($allowedStages as $allowedStage) {
+			$previousStage = $allowedStage->getPrevious();
+			$nextStage = $allowedStage->getNext();
+			if ($previousStage !== NULL && !isset($allowedStages[$previousStage->getUid()])) {
+				$allowedStages[$previousStage->getUid()] = $previousStage;
+			}
+			if ($nextStage !== NULL && !isset($allowedStages[$nextStage->getUid()])) {
+				$allowedStages[$nextStage->getUid()] = $nextStage;
+			}
+		}
+
+		uasort($allowedStages, function(StageRecord $first, StageRecord $second) { return $first->determineOrder($second); });
+		return $this->prepareStagesArray($allowedStages);
+	}
+
+	/**
+	 * Prepares simplified stages array to be used in ExtJs components.
+	 *
+	 * @param StageRecord[] $stageRecords
+	 * @return array
+	 */
+	protected function prepareStagesArray(array $stageRecords) {
+		$stagesArray = array();
+		foreach ($stageRecords as $stageRecord) {
+			$stage = array(
+				'uid' => $stageRecord->getUid(),
+				'label' => $stageRecord->getTitle(),
+			);
+			if (!$stageRecord->isExecuteStage()) {
+				$stage['title'] = $GLOBALS['LANG']->sL(($this->pathToLocallang . ':actionSendToStage')) . ' "' . $stageRecord->getTitle() . '"';
 			} else {
-				foreach ($workspaceStageRecs as $workspaceStageRec) {
-					if ($workspaceStageRec['uid'] === self::STAGE_EDIT_ID) {
-						$allowedStages[self::STAGE_EDIT_ID] = $workspaceStageRec;
-						$stagesForWSUserData[$workspaceStageRec['uid']] = $workspaceStageRec;
-					} elseif ($this->isStageAllowedForUser($workspaceStageRec['uid'])) {
-						$stagesForWSUserData[$workspaceStageRec['uid']] = $workspaceStageRec;
-					} elseif ($workspaceStageRec['uid'] == self::STAGE_PUBLISH_EXECUTE_ID && $GLOBALS['BE_USER']->workspacePublishAccess($this->getWorkspaceId())) {
-						$allowedStages[] = $workspaceStageRec;
-						$stagesForWSUserData[$workspaceStageRec['uid']] = $workspaceStageRec;
-					}
-				}
-				foreach ($stagesForWSUserData as $allowedStage) {
-					$nextStage = $this->getNextStage($allowedStage['uid']);
-					$prevStage = $this->getPrevStage($allowedStage['uid']);
-					if (isset($prevStage['uid'])) {
-						$allowedStages[$prevStage['uid']] = $prevStage;
-					}
-					if (isset($nextStage['uid'])) {
-						$allowedStages[$nextStage['uid']] = $nextStage;
-					}
-				}
-				$orderedAllowedStages = array_values($allowedStages);
+				$stage['title'] = $GLOBALS['LANG']->sL($this->pathToLocallang . ':publish_execute_action_option');
 			}
+			$stagesArray[] = $stage;
 		}
-		return $orderedAllowedStages;
+		return $stagesArray;
 	}
 
 	/**
@@ -406,95 +409,129 @@ class StagesService {
 	}
 
 	/**
-	 * Get array of all responsilbe be_users for a stage
+	 * Gets all backend user records that are considered to be responsible
+	 * for a particular stage or workspace.
 	 *
-	 * @param int $stageId Stage id
+	 * @param StageRecord|int $stageRecord Stage
 	 * @param bool $selectDefaultUserField If field notification_defaults should be selected instead of responsible users
 	 * @return array be_users with e-mail and name
 	 */
-	public function getResponsibleBeUser($stageId, $selectDefaultUserField = FALSE) {
-		$workspaceRec = BackendUtility::getRecord('sys_workspace', $this->getWorkspaceId());
+	public function getResponsibleBeUser($stageRecord, $selectDefaultUserField = FALSE) {
+		if (!$stageRecord instanceof StageRecord) {
+			$stageRecord = $this->getWorkspaceRecord()->getStage($stageRecord);
+		}
+
 		$recipientArray = array();
-		switch ($stageId) {
-			case self::STAGE_PUBLISH_EXECUTE_ID:
 
-			case self::STAGE_PUBLISH_ID:
-				if (!$selectDefaultUserField) {
-					$userList = $this->getResponsibleUser($workspaceRec['adminusers'] . ',' . $workspaceRec['members']);
-				} else {
-					$notification_default_user = $workspaceRec['publish_notification_defaults'];
-					$userList = $this->getResponsibleUser($notification_default_user);
-				}
-				break;
-			case self::STAGE_EDIT_ID:
-				if (!$selectDefaultUserField) {
-					$userList = $this->getResponsibleUser($workspaceRec['adminusers'] . ',' . $workspaceRec['members']);
-				} else {
-					$notification_default_user = $workspaceRec['edit_notification_defaults'];
-					$userList = $this->getResponsibleUser($notification_default_user);
-				}
-				break;
-			default:
-				if (!$selectDefaultUserField) {
-					$responsible_persons = $this->getPropertyOfCurrentWorkspaceStage($stageId, 'responsible_persons');
-					$userList = $this->getResponsibleUser($responsible_persons);
-				} else {
-					$notification_default_user = $this->getPropertyOfCurrentWorkspaceStage($stageId, 'notification_defaults');
-					$userList = $this->getResponsibleUser($notification_default_user);
-				}
-		}
-		if (!empty($userList)) {
-			$userRecords = BackendUtility::getUserNames(
-				'username, uid, email, realName',
-				'AND uid IN (' . $userList . ')' . BackendUtility::BEenableFields('be_users')
-			);
+		if (!$selectDefaultUserField) {
+			$backendUserIds = $stageRecord->getAllRecipients();
+		} else {
+			$backendUserIds = $stageRecord->getDefaultRecipients();
 		}
-		if (!empty($userRecords) && is_array($userRecords)) {
-			foreach ($userRecords as $userUid => $userRecord) {
-				$recipientArray[$userUid] = $userRecord;
-			}
+
+		$userList = implode(',', $backendUserIds);
+		$userRecords = $this->getBackendUsers($userList);
+		foreach ($userRecords as $userUid => $userRecord) {
+			$recipientArray[$userUid] = $userRecord;
 		}
 		return $recipientArray;
 	}
 
 	/**
-	 * Get uids of all responsilbe persons for a stage
+	 * Gets backend user ids from a mixed list of backend users
+	 * and backend users groups. This is used for notifying persons
+	 * responsible for a particular stage or workspace.
 	 *
 	 * @param string $stageRespValue Responsible_person value from stage record
-	 * @return string Uid list of responsible be_users
+	 * @return string List of backend user ids
 	 */
 	public function getResponsibleUser($stageRespValue) {
-		$stageValuesArray = GeneralUtility::trimExplode(',', $stageRespValue, TRUE);
-		$beuserUidArray = array();
-		$begroupUidArray = array();
+		return implode(',', $this->resolveBackendUserIds($stageRespValue));
+	}
+
+	/**
+	 * Resolves backend user ids from a mixed list of backend users
+	 * and backend user groups (e.g. "be_users_1,be_groups_3,be_users_4,...")
+	 *
+	 * @param string $backendUserGroupList
+	 * @return array
+	 */
+	public function resolveBackendUserIds($backendUserGroupList) {
+		$elements = GeneralUtility::trimExplode(',', $backendUserGroupList, TRUE);
+		$backendUserIds = array();
+		$backendGroupIds = array();
 
-		foreach ($stageValuesArray as $uidvalue) {
-			if (strstr($uidvalue, 'be_users') !== FALSE) {
+		foreach ($elements as $element) {
+			if (strpos($element, 'be_users_') === 0) {
 				// Current value is a uid of a be_user record
-				$beuserUidArray[] = str_replace('be_users_', '', $uidvalue);
-			} elseif (strstr($uidvalue, 'be_groups') !== FALSE) {
-				$begroupUidArray[] = str_replace('be_groups_', '', $uidvalue);
-			} elseif ((int)$uidvalue) {
-				$beuserUidArray[] = (int)$uidvalue;
+				$backendUserIds[] = str_replace('be_users_', '', $element);
+			} elseif (strpos($element, 'be_groups_') === 0) {
+				$backendGroupIds[] = str_replace('be_groups_', '', $element);
+			} elseif ((int)$element) {
+				$backendUserIds[] = (int)$element;
 			}
 		}
 
-		if (!empty($begroupUidArray)) {
+		if (!empty($backendGroupIds)) {
 			$allBeUserArray = BackendUtility::getUserNames();
-			$begroupUidList = implode(',', $begroupUidArray);
+			$backendGroupList = implode(',', $backendGroupIds);
 			$this->userGroups = array();
-			$begroupUidArray = $this->fetchGroups($begroupUidList);
-			foreach ($begroupUidArray as $groupkey => $groupData) {
-				foreach ($allBeUserArray as $useruid => $userdata) {
-					if (GeneralUtility::inList($userdata['usergroup_cached_list'], $groupData['uid'])) {
-						$beuserUidArray[] = $useruid;
+			$backendGroups = $this->fetchGroups($backendGroupList);
+			foreach ($backendGroups as $backendGroup) {
+				foreach ($allBeUserArray as $backendUserId => $backendUser) {
+					if (GeneralUtility::inList($backendUser['usergroup_cached_list'], $backendGroup['uid'])) {
+						$backendUserIds[] = $backendUserId;
 					}
 				}
 			}
 		}
 
-		array_unique($beuserUidArray);
-		return implode(',', $beuserUidArray);
+		return array_unique($backendUserIds);
+	}
+
+	/**
+	 * Gets backend user records from a given list of ids.
+	 *
+	 * @param string $backendUserList
+	 * @return array
+	 */
+	public function getBackendUsers($backendUserList) {
+		if (empty($backendUserList)) {
+			return array();
+		}
+
+		$backendUserList = $this->getDatabaseConnection()->cleanIntList($backendUserList);
+		$backendUsers = BackendUtility::getUserNames(
+			'username, uid, email, realName',
+			'AND uid IN (' . $backendUserList . ')' . BackendUtility::BEenableFields('be_users')
+		);
+
+		if (empty($backendUsers)) {
+			$backendUsers = array();
+		}
+		return $backendUsers;
+	}
+
+	/**
+	 * @param StageRecord $stageRecord
+	 * @return array
+	 */
+	public function getPreselectedRecipients(StageRecord $stageRecord) {
+		if ($stageRecord->areEditorsPreselected()) {
+			return array_merge(
+				$stageRecord->getPreselectedRecipients(),
+				$this->getRecordService()->getCreateUserIds()
+			);
+		} else {
+			return $stageRecord->getPreselectedRecipients();
+		}
+	}
+
+	/**
+	 * @return WorkspaceRecord
+	 */
+	protected function getWorkspaceRecord() {
+		return WorkspaceRecord::get($this->getWorkspaceId());
 	}
 
 	/**
@@ -733,6 +770,16 @@ class StagesService {
 		}
 	}
 
+	/**
+	 * @return RecordService
+	 */
+	public function getRecordService() {
+		if (!isset($this->recordService)) {
+			$this->recordService = GeneralUtility::makeInstance(RecordService::class);
+		}
+		return $this->recordService;
+	}
+
 	/**
 	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
 	 */
@@ -740,4 +787,11 @@ class StagesService {
 		return $GLOBALS['BE_USER'];
 	}
 
+	/**
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
 }
diff --git a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
index 947ca4700d28eede16f592c8854ef9651a2fa941..70ff4e409756587683f60ff17036b3fccb69ca8f 100644
--- a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
+++ b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace.php
@@ -179,6 +179,7 @@ return array(
 			),
 			'default' => 0
 		),
+		// @deprecated not used anymore
 		'edit_notification_mode' => array(
 			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.edit_notification_mode',
 			'config' => array(
@@ -191,8 +192,8 @@ return array(
 			)
 		),
 		'edit_notification_defaults' => array(
-			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.edit_notification_defaults',
-			'displayCond' => 'FIELD:edit_notification_mode:IN:0,1',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace_stage.notification_defaults',
+			'displayCond' => 'FIELD:edit_allow_notificaton_settings:BIT:1',
 			'config' => array(
 				'type' => 'group',
 				'internal_type' => 'db',
@@ -210,12 +211,31 @@ return array(
 			)
 		),
 		'edit_allow_notificaton_settings' => array(
-			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.edit_allow_notificaton_settings',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog',
 			'config' => array(
 				'type' => 'check',
-				'default' => 1
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.showDialog', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.changeablePreselection', ''),
+				),
+				'default' => 3,
+				'cols' => 2,
+			)
+		),
+		'edit_notification_preselection' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection',
+			'config' => array(
+				'type' => 'check',
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.owners', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.members', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.editors', ''),
+				),
+				'default' => 2,
+				'cols' => 3,
 			)
 		),
+		// @deprecated not used anymore
 		'publish_notification_mode' => array(
 			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.publish_notification_mode',
 			'config' => array(
@@ -228,8 +248,8 @@ return array(
 			)
 		),
 		'publish_notification_defaults' => array(
-			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.publish_notification_defaults',
-			'displayCond' => 'FIELD:publish_notification_mode:IN:0,1',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace_stage.notification_defaults',
+			'displayCond' => 'FIELD:publish_allow_notificaton_settings:BIT:1',
 			'config' => array(
 				'type' => 'group',
 				'internal_type' => 'db',
@@ -247,17 +267,96 @@ return array(
 			)
 		),
 		'publish_allow_notificaton_settings' => array(
-			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.publish_allow_notificaton_settings',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog',
+			'config' => array(
+				'type' => 'check',
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.showDialog', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.changeablePreselection', ''),
+				),
+				'default' => 3,
+				'cols' => 2,
+			)
+		),
+		'publish_notification_preselection' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection',
+			'config' => array(
+				'type' => 'check',
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.owners', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.members', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.editors', ''),
+				),
+				'default' => 1,
+				'cols' => 3,
+			)
+		),
+		'execute_notification_defaults' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace_stage.notification_defaults',
+			'displayCond' => 'FIELD:execute_allow_notificaton_settings:BIT:1',
+			'config' => array(
+				'type' => 'group',
+				'internal_type' => 'db',
+				'allowed' => 'be_users,be_groups',
+				'prepend_tname' => 1,
+				'size' => '3',
+				'maxitems' => '100',
+				'autoSizeMax' => 20,
+				'show_thumbs' => '1',
+				'wizards' => array(
+					'suggest' => array(
+						'type' => 'suggest'
+					)
+				)
+			)
+		),
+		'execute_allow_notificaton_settings' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog',
 			'config' => array(
 				'type' => 'check',
-				'default' => 1
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.showDialog', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.changeablePreselection', ''),
+				),
+				'default' => 3,
+				'cols' => 2,
+			)
+		),
+		'execute_notification_preselection' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection',
+			'config' => array(
+				'type' => 'check',
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.owners', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.members', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.editors', ''),
+				),
+				'default' => 3,
+				'cols' => 3,
 			)
 		)
 	),
+	'palettes' => array(
+		'stage.edit' => array(
+			'canNotCollapse' => TRUE,
+			'showitem' => 'edit_allow_notificaton_settings, edit_notification_preselection,',
+		),
+		'stage.publish' => array(
+			'canNotCollapse' => TRUE,
+			'showitem' => 'publish_allow_notificaton_settings, publish_notification_preselection,',
+		),
+		'stage.execute' => array(
+			'canNotCollapse' => TRUE,
+			'showitem' => 'execute_allow_notificaton_settings, execute_notification_preselection,',
+		)
+	),
 	'types' => array(
 		'0' => array('showitem' => 'title,description,
 			--div--;LLL:EXT:lang/locallang_tca.xlf:sys_filemounts.tabs.users,adminusers,members,
-			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.notification_settings,stagechg_notification,edit_notification_mode,edit_notification_defaults,edit_allow_notificaton_settings,publish_notification_mode,publish_notification_defaults,publish_allow_notificaton_settings,
+			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.notification_settings, stagechg_notification,
+				--palette--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xml:sys_workspace.palette.stage.edit;stage.edit, edit_notification_defaults,
+				--palette--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xml:sys_workspace.palette.stage.publish;stage.publish, publish_notification_defaults,
+				--palette--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xml:sys_workspace.palette.stage.execute;stage.execute, execute_notification_defaults,
 			--div--;LLL:EXT:lang/locallang_tca.xlf:sys_filemounts.tabs.mountpoints,db_mountpoints,file_mountpoints,
 			--div--;LLL:EXT:lang/locallang_tca.xlf:sys_filemounts.tabs.publishing,publish_time,unpublish_time,
 			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_filemounts.tabs.staging,custom_stages,
diff --git a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace_stage.php b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace_stage.php
index fd4813c0a268e9e1d78ef78ee270206a8c2cebff..ebc9c768c2057d2480aa26c8aaafd48c494b07f8 100644
--- a/typo3/sysext/workspaces/Configuration/TCA/sys_workspace_stage.php
+++ b/typo3/sysext/workspaces/Configuration/TCA/sys_workspace_stage.php
@@ -78,7 +78,7 @@ return array(
 		),
 		'notification_defaults' => array(
 			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace_stage.notification_defaults',
-			'displayCond' => 'FIELD:notification_mode:IN:0,1',
+			'displayCond' => 'FIELD:allow_notificaton_settings:BIT:1',
 			'config' => array(
 				'type' => 'group',
 				'internal_type' => 'db',
@@ -96,16 +96,41 @@ return array(
 			)
 		),
 		'allow_notificaton_settings' => array(
-			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace_stage.allow_notificaton_settings',
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog',
 			'config' => array(
 				'type' => 'check',
-				'default' => 1
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.showDialog', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.settingsDialog.changeablePreselection', ''),
+				),
+				'default' => 3,
+				'cols' => 2,
+			)
+		),
+		'notification_preselection' => array(
+			'label' => 'LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection',
+			'config' => array(
+				'type' => 'check',
+				'items' => array(
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.owners', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.members', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.editors', ''),
+					array('LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:sys_workspace.preselection.responsiblePersons', ''),
+				),
+				'default' => 8,
+				'cols' => 4,
 			)
 		)
 	),
+	'palettes' => array(
+		'stage' => array(
+			'canNotCollapse' => TRUE,
+			'showitem' => 'allow_notificaton_settings, notification_preselection,',
+		)
+	),
 	'types' => array(
 		'0' => array('showitem' => '
 			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.general,title,responsible_persons,
-			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.notification_settings,notification_mode,notification_defaults,allow_notificaton_settings,default_mailcomment')
+			--div--;LLL:EXT:workspaces/Resources/Private/Language/locallang_db.xlf:tabs.notification_settings,--palette--;;stage, notification_defaults, default_mailcomment')
 	)
 );
diff --git a/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf b/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
index cead9329d9f74875087eb07433f115c788262d33..0f6dcb266111ac3285294ad60305c5ba57aa7390 100644
--- a/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
+++ b/typo3/sysext/workspaces/Resources/Private/Language/locallang_db.xlf
@@ -57,6 +57,9 @@
 			<trans-unit id="tabs.general">
 				<source>General</source>
 			</trans-unit>
+			<trans-unit id="sys_workspace.execute_notification_defaults">
+				<source>Publishing execute stage: default notification mail recipients</source>
+			</trans-unit>
 			<trans-unit id="sys_workspace_stage.notification_mode">
 				<source>Recipient suggestion checkboxes</source>
 			</trans-unit>
@@ -66,6 +69,39 @@
 			<trans-unit id="sys_workspace_stage.allow_notificaton_settings">
 				<source>Allow notification settings during stage change</source>
 			</trans-unit>
+			<trans-unit id="sys_workspace.palette.stage.edit">
+				<source>Stage "editing":</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.palette.stage.publish">
+				<source>Stage "ready to publish":</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.palette.stage.execute">
+				<source>Stage "publishing execute":</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.settingsDialog">
+				<source>Settings dialog</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.settingsDialog.showDialog">
+				<source>show dialog</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.settingsDialog.changeablePreselection">
+				<source>changeable preselection</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.preselection">
+				<source>Preselection</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.preselection.owners">
+				<source>owners</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.preselection.members">
+				<source>members</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.preselection.editors">
+				<source>editors</source>
+			</trans-unit>
+			<trans-unit id="sys_workspace.preselection.responsiblePersons">
+				<source>responsible persons</source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
index 25eccdba405e28d02b6af890cd8228e55b66cf18..13e2ecdbd9352991c862ba19fa72c1f2a7a2f652 100644
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
+++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
@@ -172,7 +172,13 @@ TYPO3.Workspaces.Actions = {
 		});
 	},
 	sendToSpecificStageWindow: function(selection, nextStage) {
-		TYPO3.Workspaces.ExtDirectActions.sendToSpecificStageWindow(nextStage, function(response) {
+		var elements = [];
+
+		Ext.each(selection, function(row) {
+			elements.push({table: row.json.table, uid: row.json.uid})
+		});
+
+		TYPO3.Workspaces.ExtDirectActions.sendToSpecificStageWindow(nextStage, elements, function(response) {
 			TYPO3.Workspaces.Actions.currentSendToMode = 'specific';
 			TYPO3.Workspaces.Actions.sendToStageWindow(response, selection);
 		});
diff --git a/typo3/sysext/workspaces/ext_tables.sql b/typo3/sysext/workspaces/ext_tables.sql
index c97bf906683141fd383d5f02e2218aed3b1fa4ee..ebc980bb82235f28c905e766309bed2a2525e920 100644
--- a/typo3/sysext/workspaces/ext_tables.sql
+++ b/typo3/sysext/workspaces/ext_tables.sql
@@ -24,10 +24,16 @@ CREATE TABLE sys_workspace (
 	stagechg_notification tinyint(3) DEFAULT '0' NOT NULL,
 	edit_notification_mode tinyint(3) DEFAULT '0' NOT NULL,
 	edit_notification_defaults varchar(255) DEFAULT '' NOT NULL,
+	edit_notification_preselection tinyint(3) DEFAULT '3' NOT NULL,
 	edit_allow_notificaton_settings tinyint(3) DEFAULT '0' NOT NULL,
 	publish_notification_mode tinyint(3) DEFAULT '0' NOT NULL,
 	publish_notification_defaults varchar(255) DEFAULT '' NOT NULL,
+	publish_notification_preselection tinyint(3) DEFAULT '3' NOT NULL,
 	publish_allow_notificaton_settings tinyint(3) DEFAULT '0' NOT NULL,
+	execute_notification_mode tinyint(3) DEFAULT '0' NOT NULL,
+	execute_notification_defaults varchar(255) DEFAULT '' NOT NULL,
+	execute_notification_preselection tinyint(3) DEFAULT '3' NOT NULL,
+	execute_allow_notificaton_settings tinyint(3) DEFAULT '0' NOT NULL,
 
 	PRIMARY KEY (uid),
 	KEY parent (pid)
@@ -51,6 +57,7 @@ CREATE TABLE sys_workspace_stage (
 	notification_mode tinyint(3) DEFAULT '0' NOT NULL,
 	notification_defaults varchar(255) DEFAULT '' NOT NULL,
 	allow_notificaton_settings tinyint(3) DEFAULT '0' NOT NULL,
+	notification_preselection tinyint(3) DEFAULT '8' NOT NULL,
 
 	PRIMARY KEY (uid),
 	KEY parent (pid)