 
 					if let indexPaths = changes.insertedRows {
 						tableView.insertRowsAtIndexPaths(indexPaths.map { NSIndexPath(converting: $0) },
-							withRowAnimation: self.rowAnimation)
+							withRowAnimation: self.insertingAnimation)
 					}
 
 					tableView.endUpdates()
 				}
 
-				if !self.isEmpty && self.set.numberOfObjects == 0 {
+				if !self.isEmpty && self.set.map({ $0.count }).reduce(0, combine: +) == 0 {
 					self.isEmpty = true
-					self.emptySetHandler?(true)
+					self.emptiedObserver?()
 				} else if self.isEmpty {
 					self.isEmpty = false
-					self.emptySetHandler?(false)
+					self.unemptiedObserver?()
 				}
 		}
 	}
 
+	/// MARK: `UITableViewDataSource` conformance
+
 	public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
-		return set.numberOfSections
+		return set.count
 	}
 
 	public func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
-		let sectionName = set.sectionName(for: section)
-		return sectionNameTransform?(section, sectionName) ?? sectionName
+		let sectionName = set[section.typeErased()].name.value
+		return sectionNameMapper?(position: section, persistedName: sectionName) ?? sectionName
 	}
 
 	public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
 		let (reuseIdentifier, configurator) = cellConfigurators[isUniform ? 0 : indexPath.section]!
 		let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier,
 		                                                       forIndexPath: indexPath)
-		configurator(cell: cell, viewModel: set[indexPath])
+		configurator(cell: cell, viewModel: set[indexPath.section.typeErased()][indexPath.row.typeErased()])
 
 		return cell
 	}
 
 	public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-		return set.numberOfRows(for: section)
+		return set[section.typeErased()].count
 	}
 }

					if let indexSet = changes.deletedSections {
						tableView.deleteSections(NSMutableIndexSet(converting: indexSet),
							withRowAnimation: self.rowAnimation)
					}

					if let indexSet = changes.reloadedSections {
						tableView.reloadSections(NSMutableIndexSet(converting: indexSet),
							withRowAnimation: self.rowAnimation)
					}

					if let indexPaths = changes.deletedRows {
						tableView.deleteRowsAtIndexPaths(indexPaths.map { NSIndexPath(converting: $0) },
							withRowAnimation: self.rowAnimation)
					}

					if self.shouldReloadRowsForUpdatedObjects, let indexPaths = changes.updatedRows {
						tableView.reloadRowsAtIndexPaths(indexPaths.map { NSIndexPath(converting: $0) },
							withRowAnimation: self.rowAnimation)
					}

					if let indexSet = changes.insertedSections {
						tableView.insertSections(NSMutableIndexSet(converting: indexSet),
							withRowAnimation: self.rowAnimation)
					}

					if let indexPathPairs = changes.movedRows {

		return self
	}

	public func setAnimation(inserting insertingAnimation: UITableViewRowAnimation? = nil,
	                         deleting deletingAnimation: UITableViewRowAnimation? = nil,
													 updating updatingAnimation: UITableViewRowAnimation? = nil)
													 -> TableViewAdapter {
		self.insertingAnimation = insertingAnimation ?? self.insertingAnimation
		self.deletingAnimation = deletingAnimation ?? self.deletingAnimation
		self.updatingAnimation = updatingAnimation ?? self.updatingAnimation

		return self
	}

	public func mapSectionName(using transform: (position: Int, persistedName: String?) -> String?) -> TableViewAdapter {
		sectionNameMapper = transform
		return self
	}

	public func reloadUpdatedRows(enabling flag: Bool = true) -> TableViewAdapter {
		shouldReloadRowsForUpdatedObjects = flag
		return self
	}

	public func on(emptied emptied: (() -> Void)?, unemptied: (() -> Void)?) -> TableViewAdapter {
		emptiedObserver = emptied ?? emptiedObserver
		unemptiedObserver = unemptied ?? unemptiedObserver
		return self
	}

	public func bind(tableView: UITableView) -> Disposable {
		tableView.dataSource = self

