Federer also lost the number one spot in ATP rankings to Rafael Nadal, and missed a chance to earn a record 10th title at the German venue.
Federer dropped the opening set in a tiebreak but levelled by winning the second. Coric held his nerve to take victory.
The Croatian outsider ranked 34th also ended Federer's 20-match win streak on grass, which stretched to June, 2017.
The Swiss will drop to second in the world behind Rafael Nadal, who is playing no tune-up events prior to the start of Wimbledon a week from Monday.
The loss in just over two hours means came a week after Federer won his 98th title in Stuttgart.
The 21-year-old had lost twice to Federer, but played him tough in their last meeting at Indian Wells last March.
He was the first Croatian to reach the final at Halle and now owns two titles after winning in Marrakech in 2017.
Federer dropped the opening set, won the second but was unable to fight back after going down 2-4 in the third.
Coric moved out to 5-2 and completed his upset on a second match point a game later as Federer's volley hit the top of the net.
The Swiss fired a dozen aces but lost serve twice.
Federer's excellent serving in the first set - four love games, three points lost on serve - could not prevent Coric taking the opener in 57 minutes.
The Croatian withstood a Federer assault in the 11th game, which lasted for nearly 10 minutes and featured five deuces. A game later, the Swiss seed took the set into a tiebreaker.
Federer reached a 5-3 margin and sent down his fifth ace to earn a pair of set points. But Coric annulled the first with a service winner while a wild Federer backhand accounted for the other.
Second later, the Croatian seized the set on his first opportunity from a Federer backhand long.
The 20-time Grand Slam champion fought back to level by winning the second set, helped by a choke on a volley from Coric.
Trailing 4-3 and facing a break point in the eight game, the youngster raced to the net to flick over a winner on Federer's first set point, but stuffed the shot into the net. Leading 5-3, Federer squared the match in the next game as Coric hit the net again.