It doesn’t make Python backward incompatible; it does mean that if typing or mypy relies on it, it becomes incompatible with earlier versions of Python (or has to fork different code for 3.8+ that relies on type.__or__ being available and 3.7- that doesn’t have whatever functionality relies on that).
That doesn't strike me as blocker -- there are several things in the typing syntax that require a certain minimum version. E.g. type annotations require Python 3 (whereas type comments work in Python 2 too), type annotations on variables (PEP 526) require 3.6+, `from __future__ import annotations` (PEP 563) requires 3.7+.
That said I'd rather not introduce new syntax (like `T?` or `?T`) for `Optional[T]` -- let's see what we can do with the existing operators. I think `~T` looks okay. I'm currently working on annotating a very large codebase, and `Optional[T]` is so frequent that I think `T | None` would not be enough of an improvement.
Adding a default `__or__` overload to `type` seems a reasonable price to pay in 3.9, and ditto for `__invert__`. Type checkers can support this in older Python versions using PEP 563 or in type comments or in "forward references" (types hidden in string literals).
A wart will be that we can make `int | None` work but we shouldn't make `None | int` work (I don't want to add any new operator overloads to `None`, it should always be an error).
Open question: at runtime, what should `int | str` return? I don't want this to have to import the typing module. Maybe we could make a very simple `Union` builtin. This can then also be used by `~int` (which is equivalent to `int | None`).