diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
index cfec5759c5575de45c8ff5c387862a3a06a2a048..9f2e89c32f9aba4f2386e39d8be64f012f1c2071 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java
@@ -618,6 +618,42 @@ public interface MariaDbMapper {
         return statement.toString();
     }
 
+    default String tupleToRawUpdateTimestampQuery(TableDto table, TupleUpdateDto data, Timestamp tsAdd, Timestamp tsDelete)
+            throws TableMalformedException {
+        if (table.getColumns().isEmpty()) {
+            throw new TableMalformedException("Columns are not known");
+        }
+        final StringBuilder statement = new StringBuilder("UPDATE `")
+                .append(table.getDatabase().getInternalName())
+                .append("`.`")
+                .append(table.getInternalName()).append("_timestamps")
+                .append("` SET ");
+
+        // Set the two timestamp columns
+        statement.append("`").append(nameToInternalName("timestamp_add")).append("` = ?, ");
+        statement.append("`").append(nameToInternalName("timestamp_delete")).append("` = ? ");
+
+        // Set each primary key to its new value
+        for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
+            String pkColumn = pk.getColumn().getInternalName();
+            statement.append(", `").append(pkColumn).append("` = ? ");
+        }
+
+        // WHERE clause: match on database_id and the old primary key values
+        statement.append("WHERE ");
+        statement.append("`").append(nameToInternalName("database_id")).append("` = ? ");
+        for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
+            String pkColumn = pk.getColumn().getInternalName();
+            statement.append("AND `").append(pkColumn).append("` = ? ");
+        }
+        statement.append(";");
+
+        log.trace("Mapped update query for timestamp table: {}", statement.toString());
+        return statement.toString();
+    }
+
+
+
     default String tupleToRawCreateQuery(TableDto table, TupleDto data) throws TableMalformedException {
         if (table.getColumns().isEmpty()) {
             throw new TableMalformedException("Columns are not known");
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
index 7b0f7a4668c974ec0b71e037e29fe365568fe1a7..aaaf84003c47d33b34ebedc4918cf6d42c1f9c55 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java
@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
 import java.sql.*;
 import java.time.Instant;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @Log4j2
 @Service
@@ -368,31 +369,99 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi
     }
 
     @Override
-    public void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException,
-            QueryMalformedException, TableMalformedException {
+    public void updateTuple(TableDto table, TupleUpdateDto data)
+            throws SQLException, QueryMalformedException, TableMalformedException {
         log.trace("update tuple: {}", data);
-        /* prepare the statement */
         final ComboPooledDataSource dataSource = getDataSource(table);
         final Connection connection = dataSource.getConnection();
         try {
+            // Build and execute the main update query for the tuple.
             final int[] idx = new int[]{1};
-            final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.tupleToRawUpdateQuery(table, data));
-            /* set data */
+            final PreparedStatement statement = connection.prepareStatement(
+                    mariaDbMapper.tupleToRawUpdateQuery(table, data));
+
+            // Bind new values (data to be updated; may include new primary key values)
             for (Map.Entry<String, Object> entry : data.getData().entrySet()) {
                 mariaDbMapper.prepareStatementWithColumnTypeObject(statement,
-                        getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue());
+                        getColumnType(table.getColumns(), entry.getKey()),
+                        idx[0], entry.getKey(), entry.getValue());
                 idx[0]++;
             }
-            /* set key(s) */
+            // Bind old primary key values (for the WHERE clause)
             for (Map.Entry<String, Object> entry : data.getKeys().entrySet()) {
                 mariaDbMapper.prepareStatementWithColumnTypeObject(statement,
-                        getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue());
+                        getColumnType(table.getColumns(), entry.getKey()),
+                        idx[0], entry.getKey(), entry.getValue());
                 idx[0]++;
             }
-            final long start = System.currentTimeMillis();
+            long start = System.currentTimeMillis();
             statement.executeUpdate();
-            log.trace("executed statement in {} ms", System.currentTimeMillis() - start);
+            log.trace("Main update executed in {} ms", System.currentTimeMillis() - start);
             connection.commit();
+
+            // After the main update, select the system timestamps.
+            String selectQuery = mariaDbMapper.tupleToRawSelectSystemTimestampsQuery(
+                    table, TupleDto.builder().data(data.getData()).build());
+            try (PreparedStatement selectStmt = connection.prepareStatement(selectQuery);
+                 ResultSet rs = selectStmt.executeQuery()) {
+                if (rs.next()) {
+                    // Retrieve the new primary key values from the updated row (if needed).
+                    Map<String, Object> pkData = new HashMap<>();
+                    for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
+                        pkData.put(pk.getColumn().getInternalName(),
+                                rs.getObject(pk.getColumn().getInternalName()));
+                    }
+                    Timestamp tsAdd = rs.getTimestamp("ROW_START");
+                    Timestamp tsDelete = rs.getTimestamp("ROW_END");
+
+                    // Build the update query for the _timestamps table.
+                    String updateTsQuery = mariaDbMapper.tupleToRawUpdateTimestampQuery(
+                            table, data, tsAdd, tsDelete);
+                    try (PreparedStatement ps = connection.prepareStatement(updateTsQuery)) {
+                        int parameterIndex = 1;
+
+                        // SET clause: new timestamp values.
+                        ps.setTimestamp(parameterIndex++, tsAdd);
+                        ps.setTimestamp(parameterIndex++, tsDelete);
+
+                        // SET clause: new primary key values (assumed to be provided in data.getData())
+                        for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
+                            log.info("Setting new primary key value: {}", pk.getColumn().getInternalName());
+                            Object newPkValue = data.getData().get(pk.getColumn().getInternalName());
+                            log.info("New primary key value: {}", newPkValue);
+                            ps.setObject(parameterIndex++, newPkValue);
+                        }
+
+                        // WHERE clause: bind the database id.
+                        String databaseId = table.getDatabase().getInternalName();
+                        ps.setString(parameterIndex++, databaseId);
+
+                        // WHERE clause: bind the old primary key values.
+                        for (PrimaryKeyDto pk : table.getConstraints().getPrimaryKey()) {
+                            log.info("Setting new primary key value: {}", pk.getColumn().getInternalName());
+                            Object oldPkValue = data.getKeys().get(pk.getColumn().getInternalName());
+                            log.info("Old primary key value: {}", oldPkValue);
+                            ps.setObject(parameterIndex++, oldPkValue);
+                        }
+
+                        log.info("SQL Query: " + updateTsQuery);
+                        log.info("Bound parameters: tsAdd={}, tsDelete={}, newPKValues={}, databaseId={}, oldPKValues={}",
+                                tsAdd, tsDelete,
+                                table.getConstraints().getPrimaryKey().stream()
+                                        .map(pk -> data.getData().get(pk.getColumn().getInternalName()))
+                                        .collect(Collectors.toList()),
+                                databaseId,
+                                table.getConstraints().getPrimaryKey().stream()
+                                        .map(pk -> data.getKeys().get(pk.getColumn().getInternalName()))
+                                        .collect(Collectors.toList()));
+
+                        int rowsUpdated = ps.executeUpdate();
+                        log.info("Updated {} row(s) in {}_timestamps table.", rowsUpdated, table.getInternalName());
+                    }
+                } else {
+                    log.warn("No row found for updated PK; timestamps not updated.");
+                }
+            }
         } catch (SQLException e) {
             connection.rollback();
             log.error("Failed to update tuple: {}", e.getMessage());
@@ -403,6 +472,7 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi
         log.info("Updated tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName());
     }
 
+
     public ColumnTypeDto getColumnType(List<ColumnDto> columns, String name) throws QueryMalformedException {
         final Optional<ColumnDto> optional = columns.stream()
                 .filter(c -> c.getInternalName().equals(name)).findFirst();