Doesn't this have the same problems as the DELETE+INSERT from OP? Namely, a concurrently executing transaction will see a brief moment in time where no valid (e.g. CreatedOn < NOW() < InvalidatedOn) UserProfile exists.
There's also a bunch of weird corner cases you need to expect. For example, you can have multiple valid UserProfile objects at once if two transactions insert concurrently. If you LIMIT 1 and sort by CreatedOn that may not be a huge issue, but it will look weird if you try to look at historical data.