Nothing directly prevents it in Bitcoin, and indeed the attack has been demonstrated on testnet3 many times---it's the primary reason that testnet3 currently has almost three times as many blocks as Bitcoin, despite being launched several years after Bitcoin mainnet and with a something similar to Bitcoin's 10-minute average block interval.
Indirectly, there are several reasons the time warp attack is less practical on Bitcoin mainnet than testnet3 or altcoins like Verge:
Obvious: once blocks used in a time-warp attack are broadcast, anyone can see that median-time-past (the monotonic clock in Bitcoin) is lagging far behind real time.
Slow: the time warp attack exploits the formula used for retargeting, but retargeting only runs once every 2,016 blocks (two weeks at normal rate) and can only reduce difficulty by a maximum of 75% per period. Now, 75% is a lot, but so is spending two weeks executing a publicly-visible attack. Further difficulty decreases can be executed faster due to the modified difficulty, but they're still pretty slow: 3.5 days for the second retarget; about 1 day for the third; about 6 hours for the fourth; etc...
Easily fixable by miners: if honest miners control the majority of the hashrate, they can simply refuse to build on top of blocks whose timestamps are too far in the past. If median-time-past is restored to its normal trailing average before the end of the initial 2,016-block retarget period, difficulty won't be changed any more than normal.
If all these reasons do indeed provide indirect mitigation, then why do we see the attack on testnet3 every few months? Mainly because testnet3 uses the same SHA256d proof of work function as Bitcoin and so anyone who wants to mine blocks really quick can hook up some modern ASIC miners to create a bunch of testnet blocks quickly. This would normally rapidly increase difficulty, but the increase is prevented using the time warp attack. That said, in at least one case in the past where a time warp attacker made testnet3 unusable for an extended amount of time, some generous person pointed their own huge mining rig at testnet3 to overwhelm the attacker and bring difficulty back up.
On Bitcoin mainnet, if the attack was ever executed, I think the story would be different. Within days, a large percentage of the userbase would know the attack was ramping up and would start to pressure honest miners to reject the attacker's blocks. I personally expect miners would comply (as the next step would be for people to start throwing around phrases like "PoW function change"), which would defeat the attacker and cost him expected revenue for every rejected block.
If attackers expect the scenario would play out basically the same way I think it would, then there's no point in them starting the attack in the first place---which I think is what ultimately prevents time warp attacks on Bitcoin.
 Testnet3, unlike Bitcoin, has a rule that if no block has been mined within 20 minutes (according to block header time), that a miner can create a difficulty-1 block (the lowest difficulty). That means that even completely honest mining on testnet3 is faster than on mainnet, as on mainnet something like 20% of blocks take longer than 20 minutes to find.
Some extra notes:
A fork could change the retarget calculation to use median-time-past instead of raw block header time. This could fix the time warp attack on Bitcoin, but it would probably have to be a hard fork.
Since the BIP113 soft fork, median-time-past has been used to restrict which nLockTime transactions miners can include in their blocks. Not many transactions use nLockTime with a time at present, but if there was a time warp attack, users could start doing so to create a large fee incentive for miners to bring median-time-past closer to real time.