After the big swing in iOS 18 — #Index, #Unique, custom DataStore backends, and the history API — iOS 26 is a quiet release for SwiftData. There is exactly one substantial addition: class inheritance for @Model types, plus the schema migration machinery needed to adopt it safely. If you were hoping for CloudKit sharing options or dynamic predicates, they didn't ship this cycle.
#Model inheritance
Before iOS 26, every @Model type had to stand alone — no subclassing. That restriction is gone. A base class can now be subclassed by other @Model classes, which is the obvious fit for a natural hierarchy: a Trip base class with BusinessTrip and PersonalTrip variants that each add their own fields.
@Model
class Trip {
var name: String
var destination: String
var startDate: Date
var endDate: Date
init(name: String, destination: String, startDate: Date, endDate: Date) {
self.name = name
self.destination = destination
self.startDate = startDate
self.endDate = endDate
}
}
@available(iOS 26, *)
@Model
final class BusinessTrip: Trip {
var costCenter: String
init(name: String, destination: String, startDate: Date, endDate: Date, costCenter: String) {
self.costCenter = costCenter
super.init(name: name, destination: destination, startDate: startDate, endDate: endDate)
}
}
Use it when two or more models genuinely share fields and behavior and you'd otherwise be duplicating properties, or reaching for a shared protocol that still duplicates storage.
#Fetching and querying across a hierarchy
Fetch the base type and SwiftData returns instances of whatever subclass each row actually is — a single FetchDescriptor<Trip> gives you polymorphic results, not just base-class data. Filtering still runs through #Predicate against the base type's shared properties; to filter on a subclass's own fields you fetch or query that subclass type specifically. If your app logic already treats trips generically and only occasionally needs business-specific fields, this is the model to reach for instead of bolting optional properties onto one flat class.
#Migrating an existing schema to inheritance
Introducing a subclass to a model you already ship is a schema change, so it goes through the same VersionedSchema / MigrationStage / SchemaMigrationPlan machinery SwiftData has used since iOS 17 — nothing new there, but you will need to touch it. Add the subclass to your latest schema version's model list and add a migration stage from the previous version:
enum SchemaV1: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] { [Trip.self] }
}
enum SchemaV2: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] { [Trip.self, BusinessTrip.self] }
}
enum TripMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] { [SchemaV1.self, SchemaV2.self] }
static var stages: [MigrationStage] {
[.lightweight(fromVersion: SchemaV1.self, toVersion: SchemaV2.self)]
}
}
A lightweight stage is enough when you're only adding a new subclass with no existing rows to reshape. Reach for .custom if you're also reclassifying existing Trip rows into the new subclass.
#Availability and deployment target reality
Inheritance is gated to iOS 26 and later — the subclass declarations need @available(iOS 26, *), and so does any code path that constructs or fetches them. If your app still supports iOS 17 through 25, you're maintaining two shapes of the model conceptually until you can drop the older targets; there's no fallback that lets an older OS gracefully see only the base type.
#What didn't change this year
Worth saying plainly, since a lot of writeups blur consecutive releases together: #Index, #Unique, the custom DataStore protocol, and ModelContext.fetchHistory all shipped in iOS 18, not iOS 26. If your app already targets iOS 18+, those were already available to you and aren't new for this release — don't credit iOS 26 for work you can already ship today.
#What to adopt first
- No natural class hierarchy in your models today? There's nothing here to adopt — skip this release and move on.
- If you do have one, and your minimum deployment target is already iOS 26, inheritance is worth using to kill duplicated properties across near-identical models.
- On a mixed deployment target, write the migration plan now but gate the subclass types behind
@availableand ship the base-only schema to older OS versions until you can raise the floor. - Don't chase "new" SwiftData features that are actually iOS 18 holdovers —
#Indexand#Uniqueare worth using regardless, just don't expect this release to have added to them.