Implementations of language constructs over transactional memory have typically provided unexpected semantics, required the re-compilation of non-transacted code, or assumed new hardware. We introduce an alternative approach founded on a contract between the programmer and the language implementation in which strong semantics are provided to programs that are “correctly synchronized” in their use of the language, even if the underlying TM implementation provides weaker guarantees. Our approach is based on the dynamic separation of objects that can be updated in transactions, objects that can be updated outside transactions, and read-only objects that are accessible everywhere. We introduce explicit operations that, at run-time, identify transitions between these modes of access. Dynamic separation is more flexible than earlier notions of static separation, while still permitting an extremely wide range of hardware-based and software-based implementations. We define what it means for a program to obey the dynamic-separation discipline, and we show how a run-time checking tool – analogous to a data-race detector – can test this property. We also describe our design and implementation of a system with dynamic separation, and examine the use of dynamic separation in an asynchronous IO library.