diff --git a/src/Scaffolding/TableImplementation.php b/src/Scaffolding/TableImplementation.php
index a4f01d5da970757e42f0aa64e0806f5701dff753..e0f4c75dcd7e50964f9442e197cea165d6c75ccd 100644
--- a/src/Scaffolding/TableImplementation.php
+++ b/src/Scaffolding/TableImplementation.php
@@ -34,7 +34,6 @@ final class TableImplementation implements Capability
 	/**
 	 * @param array<string, ColumnMetadata> $columnMetadata
 	 * @param array<string, PhpType> $columnPhpTypes
-	 * @param array<string, PhpType> $primaryKeyFields
 	 */
 	public function __construct(
 		private string $schema,
@@ -44,7 +43,6 @@ final class TableImplementation implements Capability
 		private string $modificationClass,
 		private array $columnMetadata,
 		private array $columnPhpTypes,
-		private array $primaryKeyFields,
 	) {}
 
 	public function applyTo(
@@ -173,21 +171,14 @@ final class TableImplementation implements Capability
 
 
 		$newMethod = $classType->addMethod('new')
-			->setReturnType($this->rowClass)
-			->addBody('$primaryKey = ?::from(...?:);', [
-				new Code\Literal($namespace->simplifyName($this->primaryKeyClass)),
-				map(
-					$this->primaryKeyFields,
-					static fn($_, string $name) => new Code\Literal('$' . $name),
-				),
-			])
+			->setReturnType($this->modificationClass)
 			->addBody(
 				'$modifications = ?::new();',
 				[new Code\Literal($namespace->simplifyName($this->modificationClass))],
 			);
 
 		$editMethod = $classType->addMethod('edit')
-			->setReturnType($this->rowClass)
+			->setReturnType($this->modificationClass)
 			->setParameters([
 				(new Code\Parameter('rowOrKey'))->setType($this->rowClass . '|' . $this->primaryKeyClass),
 			])
@@ -202,7 +193,8 @@ final class TableImplementation implements Capability
 
 		foreach ([$newMethod, $editMethod] as $method) {
 			foreach ($columns as $columnMetadata) {
-				$hasDefaultValue = $columnMetadata->hasDefaultValue() || $method === $editMethod;
+				$isEditMethod = $method === $editMethod;
+				$hasDefaultValue = $columnMetadata->hasDefaultValue() || $isEditMethod;
 
 				$fieldName = $columnMetadata->getName();
 				$fieldType = $this->columnPhpTypes[$fieldName];
@@ -254,13 +246,12 @@ final class TableImplementation implements Capability
 				}
 			}
 
-			$method->addBody('$this->save($modifications);');
-			$method->addBody('return $this->get($primaryKey);');
+			$method->addBody('return $modifications;');
 		}
 
 
 		$classType->addMethod('save')
-			->setPrivate()
+			->addComment('@deprecated')
 			->setReturnType('void')
 			->setParameters([
 				(new Code\Parameter('changes'))->setType($this->modificationClass)
@@ -269,6 +260,33 @@ final class TableImplementation implements Capability
 				'$this->tableManager->save($this, $changes);'
 			);
 
+		$classType->addMethod('insert')
+			->setReturnType('void')
+			->setParameters([
+				(new Code\Parameter('changes'))->setType($this->modificationClass),
+			])
+			->setBody(
+				'$this->tableManager->insert($this, $changes);',
+			);
+
+		$classType->addMethod('update')
+			->setReturnType('void')
+			->setParameters([
+				(new Code\Parameter('changes'))->setType($this->modificationClass),
+			])
+			->setBody(
+				'$this->tableManager->update($this, $changes);',
+			);
+
+		$classType->addMethod('insertOrUpdate')
+			->setReturnType('void')
+			->setParameters([
+				(new Code\Parameter('changes'))->setType($this->modificationClass),
+			])
+			->setBody(
+				'$this->tableManager->save($this, $changes);',
+			);
+
 		$classType->addMethod('delete')
 			->setReturnType('void')
 			->setParameters([
diff --git a/src/Scaffolding/TablesDefinitions.php b/src/Scaffolding/TablesDefinitions.php
index a6b3ff3ab5333175be08743359953ecab94de1cd..06f31a212b1aa0a33d5911828a339693b056640d 100644
--- a/src/Scaffolding/TablesDefinitions.php
+++ b/src/Scaffolding/TablesDefinitions.php
@@ -99,7 +99,6 @@ final class TablesDefinitions
 				$modificationsClassName,
 				$columnMetadata,
 				$columnPhpTypes,
-				$primaryKeyFields,
 			));
 
 		return Definitions::from($rowClass, $modificationsClass, $primaryKeyClass, $tableClass);
diff --git a/tests/CompositeTypeIntegrationTest.php b/tests/CompositeTypeIntegrationTest.php
index 3fed87f0cae044c7f6476bb04f271546d8c743ff..c8c5a59e519a11d84cb147e63ea2dffaeb149cf8 100644
--- a/tests/CompositeTypeIntegrationTest.php
+++ b/tests/CompositeTypeIntegrationTest.php
@@ -20,7 +20,9 @@ $table = new PackagesTable(
 	TestFixtures::createTypeResolver($connection),
 );
 
-$table->new('grifart/tables', [0, 8, 0], [new Version(0, 7, 0)]);
+$table->insert(
+	$table->new('grifart/tables', [0, 8, 0], [new Version(0, 7, 0)]),
+);
 
 $byVersion = $table->findBy([
 	$table->version()->is([0, 8, 0]),
diff --git a/tests/Fixtures/PackagesTable.php b/tests/Fixtures/PackagesTable.php
index fd4999bc0dd3222a6de837999f0c9237d5d104f8..7ddd3a5209f57659a6d5e989a4f295915b9b4af7 100644
--- a/tests/Fixtures/PackagesTable.php
+++ b/tests/Fixtures/PackagesTable.php
@@ -12,7 +12,7 @@ use Grifart\Tables\Column;
 use Grifart\Tables\ColumnMetadata;
 use Grifart\Tables\ColumnNotFound;
 use Grifart\Tables\Conditions\Condition;
-use Grifart\Tables\DefaultValue;
+use Grifart\Tables\DefaultOrExistingValue;
 use Grifart\Tables\Expression;
 use Grifart\Tables\OrderBy\OrderBy;
 use Grifart\Tables\RowNotFound;
@@ -140,46 +140,64 @@ final class PackagesTable implements Table
 	 * @param array{int, int, int} $version
 	 * @param Version[] $previousVersions
 	 */
-	public function new(string $name, array $version, array $previousVersions): PackageRow
+	public function new(string $name, array $version, array $previousVersions): PackageModifications
 	{
-		$primaryKey = PackagePrimaryKey::from(name: $name);
 		$modifications = PackageModifications::new();
 		$modifications->modifyName($name);
 		$modifications->modifyVersion($version);
 		$modifications->modifyPreviousVersions($previousVersions);
-		$this->save($modifications);
-		return $this->get($primaryKey);
+		return $modifications;
 	}
 
 
 	/**
-	 * @param array{int, int, int}|DefaultValue $version
-	 * @param Version[]|DefaultValue $previousVersions
+	 * @param array{int, int, int}|DefaultOrExistingValue $version
+	 * @param Version[]|DefaultOrExistingValue $previousVersions
 	 */
 	public function edit(
 		PackageRow|PackagePrimaryKey $rowOrKey,
-		string|DefaultValue $name = new DefaultValue,
-		array|DefaultValue $version = new DefaultValue,
-		array|DefaultValue $previousVersions = new DefaultValue,
-	): PackageRow
+		string|DefaultOrExistingValue $name = \Grifart\Tables\Unchanged,
+		array|DefaultOrExistingValue $version = \Grifart\Tables\Unchanged,
+		array|DefaultOrExistingValue $previousVersions = \Grifart\Tables\Unchanged,
+	): PackageModifications
 	{
 		$primaryKey = $rowOrKey instanceof PackagePrimaryKey ? $rowOrKey : PackagePrimaryKey::fromRow($rowOrKey);
 		$modifications = PackageModifications::update($primaryKey);
-		if (!$name instanceof DefaultValue) {
+		if (!$name instanceof DefaultOrExistingValue) {
 			$modifications->modifyName($name);
 		}
-		if (!$version instanceof DefaultValue) {
+		if (!$version instanceof DefaultOrExistingValue) {
 			$modifications->modifyVersion($version);
 		}
-		if (!$previousVersions instanceof DefaultValue) {
+		if (!$previousVersions instanceof DefaultOrExistingValue) {
 			$modifications->modifyPreviousVersions($previousVersions);
 		}
-		$this->save($modifications);
-		return $this->get($primaryKey);
+		return $modifications;
 	}
 
 
-	private function save(PackageModifications $changes): void
+	/**
+	 * @deprecated
+	 */
+	public function save(PackageModifications $changes): void
+	{
+		$this->tableManager->save($this, $changes);
+	}
+
+
+	public function insert(PackageModifications $changes): void
+	{
+		$this->tableManager->insert($this, $changes);
+	}
+
+
+	public function update(PackageModifications $changes): void
+	{
+		$this->tableManager->update($this, $changes);
+	}
+
+
+	public function insertOrUpdate(PackageModifications $changes): void
 	{
 		$this->tableManager->save($this, $changes);
 	}
diff --git a/tests/Fixtures/TestsTable.php b/tests/Fixtures/TestsTable.php
index c8e3b69d70545e3ce13737e4c352a19164c28e10..950875e8e13fc07de1d05c7ff484f70c5099f9a8 100644
--- a/tests/Fixtures/TestsTable.php
+++ b/tests/Fixtures/TestsTable.php
@@ -12,7 +12,7 @@ use Grifart\Tables\Column;
 use Grifart\Tables\ColumnMetadata;
 use Grifart\Tables\ColumnNotFound;
 use Grifart\Tables\Conditions\Condition;
-use Grifart\Tables\DefaultValue;
+use Grifart\Tables\DefaultOrExistingValue;
 use Grifart\Tables\Expression;
 use Grifart\Tables\OrderBy\OrderBy;
 use Grifart\Tables\RowNotFound;
@@ -136,44 +136,66 @@ final class TestsTable implements Table
 	}
 
 
-	public function new(Uuid $id, int $score, string|DefaultValue|null $details = new DefaultValue): TestRow
+	public function new(
+		Uuid $id,
+		int $score,
+		string|DefaultOrExistingValue|null $details = \Grifart\Tables\DefaultValue,
+	): TestModifications
 	{
-		$primaryKey = TestPrimaryKey::from(id: $id);
 		$modifications = TestModifications::new();
 		$modifications->modifyId($id);
 		$modifications->modifyScore($score);
-		if (!$details instanceof DefaultValue) {
+		if (!$details instanceof DefaultOrExistingValue) {
 			$modifications->modifyDetails($details);
 		}
-		$this->save($modifications);
-		return $this->get($primaryKey);
+		return $modifications;
 	}
 
 
 	public function edit(
 		TestRow|TestPrimaryKey $rowOrKey,
-		Uuid|DefaultValue $id = new DefaultValue,
-		int|DefaultValue $score = new DefaultValue,
-		string|DefaultValue|null $details = new DefaultValue,
-	): TestRow
+		Uuid|DefaultOrExistingValue $id = \Grifart\Tables\Unchanged,
+		int|DefaultOrExistingValue $score = \Grifart\Tables\Unchanged,
+		string|DefaultOrExistingValue|null $details = \Grifart\Tables\Unchanged,
+	): TestModifications
 	{
 		$primaryKey = $rowOrKey instanceof TestPrimaryKey ? $rowOrKey : TestPrimaryKey::fromRow($rowOrKey);
 		$modifications = TestModifications::update($primaryKey);
-		if (!$id instanceof DefaultValue) {
+		if (!$id instanceof DefaultOrExistingValue) {
 			$modifications->modifyId($id);
 		}
-		if (!$score instanceof DefaultValue) {
+		if (!$score instanceof DefaultOrExistingValue) {
 			$modifications->modifyScore($score);
 		}
-		if (!$details instanceof DefaultValue) {
+		if (!$details instanceof DefaultOrExistingValue) {
 			$modifications->modifyDetails($details);
 		}
-		$this->save($modifications);
-		return $this->get($primaryKey);
+		return $modifications;
 	}
 
 
-	private function save(TestModifications $changes): void
+	/**
+	 * @deprecated
+	 */
+	public function save(TestModifications $changes): void
+	{
+		$this->tableManager->save($this, $changes);
+	}
+
+
+	public function insert(TestModifications $changes): void
+	{
+		$this->tableManager->insert($this, $changes);
+	}
+
+
+	public function update(TestModifications $changes): void
+	{
+		$this->tableManager->update($this, $changes);
+	}
+
+
+	public function insertOrUpdate(TestModifications $changes): void
 	{
 		$this->tableManager->save($this, $changes);
 	}
diff --git a/tests/TableTest.php b/tests/TableTest.php
index d8ad31b5cb4932d79532b2447935f2196cddc33b..e4db509f51999f83d788b406c04fd97483286343 100644
--- a/tests/TableTest.php
+++ b/tests/TableTest.php
@@ -37,7 +37,9 @@ Assert::count(2, $all);
 $all2 = $table->findBy([]);
 Assert::equal($all, $all2);
 
-$table->new(new Uuid('9493decd-4b9c-45d6-9960-0c94dc9be353'), -5, details: '👎');
+$table->insert(
+	$table->new(new Uuid('9493decd-4b9c-45d6-9960-0c94dc9be353'), -5, details: '👎')
+);
 
 $all = $table->getAll();
 Assert::count(3, $all);
@@ -113,10 +115,13 @@ Assert::same(0, $nullDetails[0]->getScore());
 $unique = $table->getBy($table->score()->is(42));
 Assert::same(42, $unique->getScore());
 
-$updatedZero = $table->edit(
+$table->update($table->edit(
 	TestPrimaryKey::from(new Uuid('2bec3f23-a210-455c-b907-bb69a99d07b2')),
 	details: 'nada',
-);
+));
+
+$updatedZero = $table->get(TestPrimaryKey::from(new Uuid('2bec3f23-a210-455c-b907-bb69a99d07b2')));
+
 Assert::same(0, $updatedZero->getScore());
 Assert::same('nada', $updatedZero->getDetails());