diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java b/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java
index 0f9c324aee1f6c5d5222164b3f3fe0f793b26545..40bf290e4ceb96194974aca7bd0ddbf58c2fe6a9 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java
@@ -35,17 +35,17 @@ public class CheckStateTransition extends EntityStateJob {
   @Override
   protected void run() {
     try {
-      State nextState = getState();
-      if (nextState != null) {
-        checkStateValid(nextState);
+      State newState = getState();
+      if (newState != null) {
+        checkStateValid(newState);
       }
       if (getEntity() instanceof UpdateEntity) {
-        State fromState = getState(((UpdateEntity) getEntity()).getOriginal());
-        checkStateTransition(fromState, nextState);
+        State oldState = getState(((UpdateEntity) getEntity()).getOriginal());
+        checkStateTransition(oldState, newState);
       } else if (getEntity() instanceof DeleteEntity) {
-        if (nextState != null) checkFinalState(nextState);
+        if (newState != null) checkFinalState(newState);
       } else {
-        if (nextState != null) checkInitialState(nextState);
+        if (newState != null) checkInitialState(newState);
       }
     } catch (Message m) {
       getEntity().addError(m);
@@ -68,31 +68,31 @@ public class CheckStateTransition extends EntityStateJob {
   /**
    * Check if state is valid and transition is allowed.
    *
-   * @param fromState
-   * @param toState
+   * @param oldState
+   * @param newState
    * @throws Message if not
    */
-  private void checkStateTransition(State fromState, State toState) throws Message {
-    if (fromState == null && toState == null) {
+  private void checkStateTransition(State oldState, State newState) throws Message {
+    if (oldState == null && newState == null) {
       return;
-    } else if (fromState == null && toState != null) {
-      checkInitialState(toState);
+    } else if (oldState == null && newState != null) {
+      checkInitialState(newState);
       return;
-    } else if (toState == null && fromState != null) {
-      checkFinalState(fromState);
+    } else if (newState == null && oldState != null) {
+      checkFinalState(oldState);
       return;
     }
 
-    StateModel stateModel = findMatchingStateModel(fromState, toState);
+    StateModel stateModel = findMatchingStateModel(oldState, newState);
     if (stateModel == null) {
       // change from one stateModel to another
-      checkInitialState(toState);
-      checkFinalState(fromState);
+      checkInitialState(newState);
+      checkFinalState(oldState);
       return;
     }
 
     for (Transition t : stateModel.getTransitions()) {
-      if (t.fromStatesInclude(fromState) && t.toStatesInclude(toState)) {
+      if (t.isFromState(oldState) && t.isToState(newState)) {
         // TODO permissions
         return;
       }
@@ -101,14 +101,14 @@ public class CheckStateTransition extends EntityStateJob {
   }
 
   /**
-   * @param fromState
-   * @param toState
+   * @param oldState
+   * @param newState
    * @return the state model which contains both of the states.
    * @throws Message if the state model of one of the states cannot be constructed.
    */
-  private StateModel findMatchingStateModel(State fromState, State toState) throws Message {
-    if (fromState.getStateModel().equals(toState.getStateModel())) {
-      return fromState.getStateModel();
+  private StateModel findMatchingStateModel(State oldState, State newState) throws Message {
+    if (oldState.getStateModel().equals(newState.getStateModel())) {
+      return oldState.getStateModel();
     }
     return null;
   }
@@ -116,11 +116,11 @@ public class CheckStateTransition extends EntityStateJob {
   /**
    * Check if the old state is final or if the {@link FORCE_FINAL_STATE} flag is true.
    *
-   * @param fromState
+   * @param oldState
    * @throws Message if the state is not final.
    */
-  private void checkFinalState(State fromState) throws Message {
-    if (!fromState.isFinal()) {
+  private void checkFinalState(State oldState) throws Message {
+    if (!oldState.isFinal()) {
       if ("true".equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE))
           || "true".equalsIgnoreCase(getEntity().getFlag(FORCE_FINAL_STATE))) {
         // TODO permissions
@@ -134,11 +134,11 @@ public class CheckStateTransition extends EntityStateJob {
   /**
    * Check if the new state is an initial state.
    *
-   * @param toState
+   * @param newState
    * @throws Message if not
    */
-  private void checkInitialState(State toState) throws Message {
-    if (!toState.isInitial()) {
+  private void checkInitialState(State newState) throws Message {
+    if (!newState.isInitial()) {
       throw INITIAL_STATE_NOT_ALLOWED;
     }
     // TODO permissions
diff --git a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
index 0602c2025b58bba0bab4652b7654fe8cb418bba6..30a4de8e04d69ad3c4b1ea1c1ebc9a082d8f4920 100644
--- a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
+++ b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java
@@ -22,6 +22,7 @@ import org.caosdb.server.entity.wrapper.Property;
 import org.caosdb.server.entity.xml.ToElementable;
 import org.caosdb.server.jobs.EntityJob;
 import org.caosdb.server.query.Query;
+import org.caosdb.server.utils.EntityStatus;
 import org.jdom2.Element;
 
 /**
@@ -111,11 +112,19 @@ public abstract class EntityStateJob extends EntityJob {
       return null;
     }
 
-    public boolean fromStatesInclude(State previousState) {
+    /**
+     * @param previousState
+     * @return true iff the previous state is a fromState of this transition.
+     */
+    public boolean isFromState(State previousState) {
       return this.fromState.equals(previousState);
     }
 
-    public boolean toStatesInclude(State nextState) {
+    /**
+     * @param nextState
+     * @return true iff the next state is a toState of this transition.
+     */
+    public boolean isToState(State nextState) {
       return this.toState.equals(nextState);
     }
 
@@ -168,6 +177,9 @@ public abstract class EntityStateJob extends EntityJob {
    * <p>Furthermore, States are the start or end point of Transitions which belong to the same
    * StateModel. Each State can be part of several transitions at the same time.
    *
+   * <p>Note: The purpose of this should not be confused with {@link EntityStatus} which is purely
+   * for internal use.
+   *
    * @author Timm Fitschen (t.fitschen@indiscale.com)
    */
   public class State implements ToElementable {
@@ -205,6 +217,7 @@ public abstract class EntityStateJob extends EntityJob {
       return 21364234 + this.getStateName().hashCode() + this.getStateModelName().hashCode();
     }
 
+    /** Serialize this State into XML. */
     @Override
     public void addToElement(Element ret) {
       Element e = new Element(STATE_XML_TAG);
@@ -232,10 +245,18 @@ public abstract class EntityStateJob extends EntityJob {
       return this.stateModel;
     }
 
+    /**
+     * @return true iff this state is an initial state of its StateModel.
+     * @throws Message
+     */
     public boolean isInitial() throws Message {
       return Objects.equals(this, getStateModel().initialState);
     }
 
+    /**
+     * @return true iff this state is a final state of its StateModel.
+     * @throws Message
+     */
     public boolean isFinal() throws Message {
       return Objects.equals(this, getStateModel().finalState);
     }
@@ -337,6 +358,13 @@ public abstract class EntityStateJob extends EntityJob {
       return null;
     }
 
+    /**
+     * Read out the "Transition" property and create Transition instances.
+     *
+     * @param p the transition property
+     * @return a set of transitions
+     * @throws Message if the transitions could ne be created.
+     */
     private Set<Transition> createTransitions(Property p) throws Message {
       Set<Transition> result = new HashSet<>();
       try {
@@ -358,6 +386,17 @@ public abstract class EntityStateJob extends EntityJob {
       return result;
     }
 
+    /**
+     * Collect all possible states from the set of transitions.
+     *
+     * <p>This function does not perform any consistency checks. It only add all toStates and
+     * fromStates of the transitions to the result.
+     *
+     * @param transitions
+     * @param stateModel
+     * @return set of states.
+     * @throws Message
+     */
     private Set<State> getStates(Set<Transition> transitions, StateModel stateModel)
         throws Message {
       Iterator<Transition> it = transitions.iterator();
@@ -434,7 +473,6 @@ public abstract class EntityStateJob extends EntityJob {
   }
 
   protected EntityInterface getStateRecordType() throws Message {
-    // TODO this should be cached
     return retrieveValidSparseEntityByName(STATE_RECORD_TYPE_NAME);
   }
 
@@ -517,6 +555,15 @@ public abstract class EntityStateJob extends EntityJob {
     return new State(stateName, stateModel);
   }
 
+  /**
+   * Create a State instance from the value of the state property.
+   *
+   * <p>This method also retrieves the state entity from the back-end.
+   *
+   * @param p the entity's state property
+   * @return The state of the entity
+   * @throws Message
+   */
   protected State createState(Property p) throws Message {
     try {
       p.parseValue();
@@ -525,6 +572,8 @@ public abstract class EntityStateJob extends EntityJob {
 
       EntityInterface stateModelEntity = findStateModel(stateEntity);
       return new State(stateEntity, stateModelEntity);
+    } catch (Message e) {
+      throw e;
     } catch (Exception e) {
       throw COULD_NOT_CONSTRUCT_STATE_MESSAGE;
     }
diff --git a/src/main/java/org/caosdb/server/jobs/core/InitEntityState.java b/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java
similarity index 51%
rename from src/main/java/org/caosdb/server/jobs/core/InitEntityState.java
rename to src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java
index 4b1d74d9827b88bb286fac0d4a1f9b494eb803ad..e7dc54af6d6f951725cc66e6839a476ba4cdb060 100644
--- a/src/main/java/org/caosdb/server/jobs/core/InitEntityState.java
+++ b/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java
@@ -17,43 +17,75 @@ import org.caosdb.server.utils.EntityStatus;
 import org.caosdb.server.utils.Observable;
 import org.caosdb.server.utils.Observer;
 
+/**
+ * Initialize the other entity jobs by converting the client message with type "State" into {@link
+ * State} instances.
+ *
+ * <p>This job also needs to initialize the other jobs even if the current entity version does not
+ * have a state anymore but the previous version had, because it has to be checked if the stateModel
+ * allows to leave in this state.
+ *
+ * @author Timm Fitschen (t.fitschen@indiscale.com)
+ */
 @JobAnnotation(
     loadAlways = true,
     time = JobExecutionTime.INIT,
     transaction = WriteTransaction.class)
-public class InitEntityState extends EntityStateJob implements Observer {
+public class InitEntityStateJobs extends EntityStateJob implements Observer {
 
   @Override
   protected void run() {
+    State newState = handleNewState();
+    handleOldState(newState);
+  }
+
+  /**
+   * Converts the state property of the original entity into a state message (only needed for
+   * updates).
+   *
+   * <p>Also, this method adds an observer to the entity state which handles a corner case where the
+   * entity changes the state, but no other property changes. In this case Update.deriveUpdate
+   * cannot detect any changes and will mark this entity as "to-be-skipped". The observer waits for
+   * that to happen and changes the {@EntityStatus} back to normal.
+   *
+   * @param newState
+   */
+  private void handleOldState(State newState) {
     try {
-      State newState = null;
-      {
-        List<State> states = initStateMessage(getEntity());
-        if (states.size() > 1) {
-          throw new Message(
-              MessageType.Error, "Currently, each entity can only have one state at a time.");
-        } else if (states.size() == 1) {
-          newState = states.get(0);
+      if (getEntity() instanceof UpdateEntity) {
+        List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
+        State oldState = null;
+        if (states.size() == 1) {
+          oldState = states.get(0);
         }
-      }
-      try {
-        if (getEntity() instanceof UpdateEntity) {
-          List<State> states = initStateMessage(((UpdateEntity) getEntity()).getOriginal());
-          State oldState = null;
-          if (states.size() == 1) {
-            oldState = states.get(0);
-          }
-          if (!Objects.equals(newState, oldState)) {
-            getEntity().acceptObserver(this);
-          }
+        if (!Objects.equals(newState, oldState)) {
+          getEntity().acceptObserver(this);
         }
-      } catch (Message m) {
-        getEntity().addWarning(STATE_ERROR_IN_ORIGINAL_ENTITY(m));
+      }
+    } catch (Message m) {
+      getEntity().addWarning(STATE_ERROR_IN_ORIGINAL_ENTITY(m));
+    }
+  }
+
+  /**
+   * Converts the state property of this entity into a state message.
+   *
+   * @return The new state.
+   */
+  private State handleNewState() {
+    State newState = null;
+    try {
+      List<State> states = initStateMessage(getEntity());
+      if (states.size() > 1) {
+        throw new Message(
+            MessageType.Error, "Currently, each entity can only have one state at a time.");
+      } else if (states.size() == 1) {
+        newState = states.get(0);
       }
     } catch (Message m) {
       getEntity().addError(m);
-      return;
     }
+    return newState;
   }
 
   private static final Message STATE_ERROR_IN_ORIGINAL_ENTITY(Message m) {
@@ -61,6 +93,13 @@ public class InitEntityState extends EntityStateJob implements Observer {
         MessageType.Warning, "State error in previous entity version\n" + m.getDescription());
   }
 
+  /**
+   * Returns a list of states as the are represented as properties or client messages in the entity.
+   *
+   * @param entity
+   * @return list of state instances for the entity.
+   * @throws Message
+   */
   private List<State> initStateMessage(EntityInterface entity) throws Message {
     List<ClientMessage> stateClientMessages = getStateClientMessages(entity, true);
     List<State> result = new ArrayList<>();